Metadata-Version: 2.4
Name: skelpr
Version: 0.2.1
Summary: Agent-agnostic code-intelligence and safe-validation backend with hybrid retrieval, file:line citations, and MCP agent integration.
Author: Thrive360, Hashim Kalam
License-Expression: LicenseRef-Proprietary
Project-URL: Homepage, https://github.com/skelpr-thrive360/skelpr
Project-URL: Repository, https://github.com/skelpr-thrive360/skelpr
Project-URL: Issues, https://github.com/skelpr-thrive360/skelpr/issues
Keywords: mcp,model-context-protocol,agents,ai-agents,claude,cursor,code-intelligence,code-review,rag,hybrid-search,embeddings,retrieval,static-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Environment :: Console
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
License-File: THIRD_PARTY_NOTICES.md
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13.7
Requires-Dist: pydantic>=2.6
Requires-Dist: pydantic-settings>=2.2
Requires-Dist: pyyaml>=6.0
Requires-Dist: httpx>=0.27
Requires-Dist: cryptography>=42
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == "postgres"
Provides-Extra: vector
Requires-Dist: qdrant-client>=1.9; extra == "vector"
Provides-Extra: ast
Requires-Dist: tree-sitter>=0.21; extra == "ast"
Requires-Dist: tree-sitter-languages>=1.10; extra == "ast"
Provides-Extra: server
Requires-Dist: fastapi>=0.110; extra == "server"
Requires-Dist: uvicorn[standard]>=0.29; extra == "server"
Provides-Extra: mcp
Requires-Dist: mcp>=2.0; extra == "mcp"
Provides-Extra: dev
Requires-Dist: skelpr[server]; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: bandit>=1.7; extra == "dev"
Requires-Dist: markdown>=3.6; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: pylint>=3.2; extra == "dev"
Provides-Extra: all
Requires-Dist: skelpr[postgres]; extra == "all"
Requires-Dist: skelpr[vector]; extra == "all"
Requires-Dist: skelpr[ast]; extra == "all"
Requires-Dist: skelpr[server]; extra == "all"
Requires-Dist: skelpr[mcp]; extra == "all"
Dynamic: license-file

<div align="center">

<!-- Hero art: drop the file in `assets/` and uncomment. Nothing else is missing.
<img src="assets/skelpr-hero.png" alt="Skelpr — surgical code retrieval for AI agents" width="100%"/>
-->

<h1>Skelpr</h1>

### Surgical code retrieval for AI agents, PR reviews, and fixes: **59% fewer tokens**, **76% fewer file reads**, and no accuracy loss.

<p>
  <a href="https://github.com/skelpr-thrive360/skelpr/actions/workflows/ci.yml"><img src="https://github.com/skelpr-thrive360/skelpr/actions/workflows/ci.yml/badge.svg?style=for-the-badge" alt="CI"/></a>
  <a href="https://pypi.org/project/skelpr/"><img src="https://img.shields.io/pypi/v/skelpr?style=for-the-badge&logo=pypi&logoColor=white&label=pypi" alt="PyPI version"/></a>
  <a href="https://pypi.org/project/skelpr/"><img src="https://img.shields.io/pypi/dm/skelpr?style=for-the-badge&logo=pypi&logoColor=white&label=downloads" alt="PyPI downloads"/></a>
  <a href="#requirements"><img src="https://img.shields.io/badge/python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python 3.10+"/></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-proprietary-red?style=for-the-badge" alt="License: proprietary"/></a>
  <a href="#development"><img src="https://img.shields.io/badge/coverage-95.10%25-brightgreen.svg?style=for-the-badge" alt="Coverage"/></a>
</p>

| Metric (agent A/B) | Agent without Skelpr | Agent with Skelpr |
|---|---|---|
| Agent tokens | 766k | **312k** (−59%) |
| Cache-read tokens | baseline | **−69%** |
| File reads | 113 | **27** (−76%) |
| Accuracy (per-task checklist) | 619 / 700 | **621 / 700** — no loss |

<p>
  <a href="#quick-start"><img src="https://img.shields.io/badge/Get%20started-activate%20%2B%20install-E5484D?style=for-the-badge" alt="Get started"/></a>
  <a href="docs/ARCHITECTURE.md"><img src="https://img.shields.io/badge/read-architecture%20%26%20retrieval-546FFF?style=for-the-badge" alt="Architecture and retrieval"/></a>
  <a href="docs/MCP_SETUP.md"><img src="https://img.shields.io/badge/set%20up-MCP%20in%20your%20agent-5865F2?style=for-the-badge" alt="MCP setup"/></a>
</p>

</div>

Most AI coding tools dump whole files into the LLM context window: slow, expensive, and prone to hallucination. Skelpr extracts only the snippets an LLM needs. AST-aware parsing and hybrid search (lexical, vector, symbol graph) return the exact code to answer, review, patch, and validate — each result carrying a `file:line` citation.

---

## Contents

- [⚡ Measured impact](#measured-impact) — the A/B, and the two facts it does *not* claim
- [👀 See it in action](#see-it-in-action) — a cited **no**, in three searches
- [Quick start](#quick-start) — activate, `setup`, `index`, ask
- [Why Skelpr?](#why-skelpr) · [Who it's for](#who-its-for) · [How it compares](#how-it-compares)
- [Two integration modes](#two-integration-modes) — agent (MCP) or standalone
- [MCP integration](#mcp-integration) — tools, `install-mcp`, custom agents
- [Install](#install) · [Requirements](#requirements) · [Local models](#local-models)
- [CLI commands](#cli-commands) — [troubleshooting: retrieval returns nothing](#troubleshooting-retrieval-returns-nothing)
- [FAQ](#faq) · [Roadmap](#roadmap)
- [Development](#development) · [Docs](#docs) · [Contributing](#contributing)
- [Support](#support) · [License](#license)

---

## ⚡ Measured impact

**Agent mode · MCP A/B:** **−59%** agent tokens · **−76%** file reads · accuracy **619 → 621 / 700** — the same answers for a fraction of the context

Self-reported benchmarks: per-task tables, verbatim outputs and the "run it yourself" guide are in **[docs/BENCHMARK.md](docs/BENCHMARK.md)**; every answer side by side in **[docs/comparisons/COMP_ANTIGRAVITY.md](docs/comparisons/COMP_ANTIGRAVITY.md)**.

### Agent mode · A/B: what happens to a real coding agent (MCP integration)

7 tasks x 2 arms (Antigravity · Gemini 3.6 Flash Medium + Skelpr MCP vs. native tools only) on the Sock Shop microservices demo:

- 🧠 **Tokens: -59%** (766k → 312k) — cache-read tokens, the biggest quota consumer, drop **-69%**
- 📖 **File reads: -76%** (113 → 27) — one `skelpr_search` (median 0.54s) replaces ~4 native file reads
- 🎯 **Accuracy: no loss** (619 → 621 / 700, every task within the ±5 tolerance) — the run-1 gaps this engine was built to fix (Helm/ingress, the healthcheck step, 3 of 5 image sites) are closed and all 5 image sites are recovered. Not a clean sweep: two single checklist facts traded the other way (session-db ↔ Makefile; kube-state-metrics), and both arms miss the negative task's phrase (60/60). Token and file-read savings are unaffected.

### CLI mode · Standalone: agentic multi-turn vs. the hybrid engine

| Pipeline Strategy | Avg. Latency | Avg. Total Tokens | Avg. Cost / Query | Accuracy (0-100) | vs. Agentic Multi-Turn |
|---|---|---|---|---|---|
| Agentic Multi-Turn | 24.39s ⚠️ | 7,573 | $0.00200 | 88.4 / 100 | reference |
| **Skelpr Hybrid Engine** | **28.90s** ⚠️ | **3,925** (−48%) | **$0.00099** (−50%) | 85.1 / 100 | **48% fewer tokens · 50% cheaper · 4 of 7 tasks tied** |

> Same 7 questions, same model (`openai/gpt-oss-120b` on Groq), same checkout, scored by the deterministic per-task checklist (0-100); per-task detail in [docs/BENCHMARK.md](docs/BENCHMARK.md). The hybrid engine retrieves pre-ranked, cited chunks in **one** pass — one model call per task instead of two — which is where the token and cost savings come from. ⚠️ The latency figures include Groq free-tier rate-limit backoff (the Skelpr arm ran second and absorbed the waits): on the task with no throttling it answered in 1.56s vs 3.55s. Accuracy is near-parity, not better: 4 of 7 tasks tie and the agentic reference leads the other three by 5-10 points.

## 👀 See it in action

<!-- Terminal demo: drop the recording in `assets/` and uncomment.
<p align="center">
  <img src="assets/skelpr-terminal-demo.gif" alt="Three cited searches answering with a provable no" width="820"/>
</p>
-->

Real output from the A/B harness (Sock Shop repo, 2026-09-24, WITH arm). The agent asks *"does a 'recommendations' service exist?"* — three searches, ~0.7s total, and it answers with a cited **no**:

```text
$ skelpr_search "recommendation recommendations inventory service" --top-k 10

## Skelpr Search Results — 10 chunks

[GRAPH]    .skelpr/graphify/summary.txt:1-2                          architecture graph summary
[LEXICAL]  deploy/kubernetes/autoscaling/grafana-service.yaml:1-23   matched 1/4 terms, filename matches 'service'
[LEXICAL]  deploy/kubernetes/autoscaling/heapster-service.yaml:1-17  matched 1/4 terms, filename matches 'service'
[LEXICAL]  deploy/kubernetes/manifests/02-carts-svc.yml:1-5          ...

$ skelpr_search "recommendationservice inventoryservice recommendation inventory" --top-k 10

## Skelpr Search Results — 1 chunk

[GRAPH]    .skelpr/graphify/summary.txt:1-2                          architecture graph summary
```

Zero code defines a recommendations service — so the agent proves absence with three cited searches and one file read (the evaluator still scores 60/100 on both arms: it wants the literal phrase "does not exist", neither answer uses it). Full verbatim exchange: [docs/BENCHMARK.md](docs/BENCHMARK.md).

## Quick start

First, activate this machine. Skelpr is proprietary software, distributed privately to people
who have been issued a token, and it runs on an activated machine:

```bash
skelpr activate <token>   # once per machine, from your access email
skelpr license            # state, seat position, lease expiry, and which source it came from
```

Then two things must be running before the first run. Skelpr cannot start either of them for you:

1. **Docker Desktop, started and finished booting.** `skelpr setup` talks to the daemon
   (`docker info`) to start Postgres and Qdrant and to build the sandbox image. If Docker
   Desktop is installed but not running, setup stops after step 1 and says so.
2. **An embedding model server** — LM Studio serving
   `text-embedding-nomic-embed-text-v1.5` (GGUF, `Q8_0`, ~146 MB) on
   `http://127.0.0.1:1234/v1`. Without it, indexing still runs but vector recall
   degrades to a local hashing fallback. Steps: [Local models](#local-models).

```bash
cd <your-repo>

# 1. Start Docker services (Postgres + Qdrant + sandbox) — Docker Desktop must be up
skelpr setup

# 2. Configure LLM provider
skelpr init --gemini YOUR_KEY    # Google Gemini
skelpr init --openai sk-proj-..  # OpenAI
skelpr init --anthropic sk-ant-.. # Anthropic
skelpr init --openrouter YOUR_KEY # OpenRouter
skelpr init --groq gsk_...       # Groq
skelpr init --local              # Local model server

# 3. Index repository (AST chunking + hybrid indexing)
skelpr index

# 4. Query, review, or fix
skelpr ask "how does authentication token refresh work?"
skelpr review --diff origin/main...HEAD
skelpr fix --issue "ValueError in user_service.py on line 42" --apply
skelpr validate                   # Run sandboxed tests/lints
skelpr serve                      # Optional FastAPI server on :8080
```

## Why Skelpr?

- **Precision over volume** — AST-aware chunking isolates exact functions, classes, and scopes, which cuts the *lost-in-the-middle* problem that large dumps cause.
- **Small token payloads** — Point premium cloud models (OpenAI, Anthropic) at enterprise-size repositories without runaway token costs, or run fast local models (Qwen, Gemma via LM Studio/vLLM) with no context ceiling.
- **Grounded & Verifiable** — Every output includes precise `file:line` citations. Edits are verified via sandboxed validation before applying.
- **Extensible by design** — AST-based patching and state-consistency tracking for reliable edits, over a published extension seam (`skelpr.plugins`). A deployment can plug in its own scoped storage, authentication resolution, and review policy.

## Who it's for

- **Agent power-users** — give Claude Code, Cursor, Windsurf, or any MCP-compatible agent surgical, cited code access with one command.
- **Teams on paid models** — keep premium cloud LLMs for enterprise repos, at the same or better accuracy and without runaway token bills.
- **Local-first developers** — run Qwen/Gemma entirely offline via LM Studio, vLLM, or Ollama: no API keys, no context-limit ceilings, no code leaving your machine.

## Two integration modes

Most users start with **Agent (MCP)** — drop Skelpr behind the coding agent you already use, no LLM key needed. Pick **Standalone** when you want Skelpr to drive the LLM itself.

| | Agent (MCP) | Standalone Package |
|---|---|---|
| **What you get** | Surgical codebase access for your existing agent | Full ask/review/fix/validate pipeline |
| **LLM needed** | No (agent's LLM; local embeddings stay keyless) | Yes (your endpoint) |
| **Commands** | Agent calls MCP tools | `skelpr ask/fix/review/validate` |
| **Retrieval** | Skelpr (same engine) | Skelpr (same engine) |
| **Reasoning** | Agent's own LLM | Your LLM via Skelpr |
| **Best for** | Enhancing Claude Code, Cursor, Windsurf, etc. | Self-contained coding assistant |

> 🧩 Mode diagrams, the shared retrieval engine, and the fallback hierarchy: **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**

## How it compares

| Instead of … | With Skelpr |
|---|---|
| Letting agents browse/read every file | -59% agent tokens, -76% file reads, no accuracy loss in agent A/B |
| grep + clicking through files | One hybrid search returns the exact files, pre-ranked, with `path:line` citations |
| Embedding-only RAG | Deterministic-first fusion (symbol > lexical > graph > vector) — exact matches win, absence is *provable*, and paths are never hallucinated |

## MCP integration

The generic Skelpr MCP server exposes code intelligence to any MCP-compatible agent (Claude Code, Cursor, Windsurf, and more).

```bash
pip install ".[mcp]"
cd <your-repo>
skelpr setup          # one-time: verify deps (model endpoint, storage) + build sandbox image
skelpr init && skelpr index
skelpr install-mcp    # auto-detect agents, preflight check, write config
```

`install-mcp` auto-detects installed agents, warns before overwriting existing entries (`--force` to skip), and supports `--project-level` for repo-local config. Register custom agents with `skelpr register-agent "<name>" <id> --cli <cmd> --global-config <path>`.

**Available MCP tools:**

- `skelpr_search` — Hybrid code search (lexical + symbol + graph + vector); default top-5 chunks with 600-char snippets to keep agent context compact
- `skelpr_get_context` — Token-budgeted context for agent context windows (default 4000-token budget, top-8 chunks, full chunk text)
- `skelpr_find_symbol` / `skelpr_dependencies` — Symbol definition and location lookup; structural relationships and dependencies
- `skelpr_validate` — Run validation commands in isolated sandbox
- `skelpr_apply_ast_patch` — Optional AST-precise structural patching
- `skelpr_health` — System health and backend status

> 📚 Manual registration, project-level config, and troubleshooting: **[docs/MCP_SETUP.md](docs/MCP_SETUP.md)**

## Install

```bash
# Wheel only, published to PyPI, so a plain `pip install skelpr` resolves anywhere.
pip install skelpr
pip install "skelpr[postgres,vector,ast,server]"   # production backends
pip install "skelpr[mcp]"                 # MCP server support
pip install "skelpr[all]"                 # everything

# From source — the repository is private, so this needs access to it:
git clone https://github.com/skelpr-thrive360/skelpr.git skelpr && cd skelpr
pip install -e ".[all]"                    # editable dev install
pip install -e ".[dev]"                    # + pytest/ruff/mypy
```

> **Installing is public; running is licensed.** The wheel is published to PyPI, wheel-only, so
> `pip install skelpr` works on any machine with nothing else to configure. There is no source
> distribution — an sdist would ship the licence check in readable form — so
> `pip install --no-binary skelpr` finds only the wheel. The runtime gate is unchanged: a machine
> still needs `skelpr activate <token>`, and each activation spends a seat. Distribution detail:
> [docs/DISTRIBUTION.md](docs/DISTRIBUTION.md).

> **Activation.** Installing needs no account; *running* does. One token per person, one seat
> per machine: `skelpr activate <token>`, then `skelpr license` to check it. Everything else —
> seats and `deactivate`, the lease and its renewal, the environment overrides, and the limits
> of the mechanism — is in
> [docs/ACCESS.md](docs/ACCESS.md). `pip` → `activate` → `license`, plus the vendor's half of
> the handover, is one page: [docs/HANDOVER.md](docs/HANDOVER.md).

### Upgrading

```bash
skelpr upgrade --check     # what is published vs what you run (exit 1 when one is available)
skelpr upgrade             # install it, through pip, pipx or uv — whichever owns the install
```

`skelpr license` also says when a newer release exists. The check is one request a day at
most, never installs anything by itself, and is switched off by `SKELPR_NO_UPDATE_CHECK=1` —
for a CI job, or anyone who would rather this build asked nothing. A machine set to
`SKELPR_OFFLINE=1` never checks at all.

**Restart after upgrading.** The files on disk change; the processes already running do not.
Your agent holds the MCP server in its own process, and `skelpr watch`/`skelpr serve` are
daemons — each keeps running the old code until it is restarted. Run `skelpr index` as well if
the release notes mention indexing or embedding changes. An editable install is refused on
purpose: `skelpr upgrade` never replaces a working copy, so a checkout is updated with `git`.

> Why no auto-update: an unattended upgrade would swap the package under a live MCP server,
> change what a lease unlocks mid-session, and land migrations against a database the user is
> running. Better a notice nobody can miss than a version nobody chose.

## Requirements

| Requirement | Needed for | Notes |
|---|---|---|
| Python ≥ 3.10 | everything | |
| `git` on PATH | diff / review / patch | degrades without it for index / ask |
| `ripgrep` | fast lexical search | recommended; pure-Python fallback otherwise |
| **Docker Desktop, running** | `skelpr setup`, sandboxed `validate` | Start Docker Desktop first. `skelpr setup` checks the daemon with `docker info`, then starts Postgres 16 (port 5434) and Qdrant (6333/6334) and builds the `skelpr-runner:latest` sandbox image. Without Docker the core still runs end to end on in-memory fallbacks. |
| **An embeddings server** | `skelpr index` + vector retrieval, in both modes | LM Studio serving `text-embedding-nomic-embed-text-v1.5` (GGUF `Q8_0`, ~146 MB) at `http://127.0.0.1:1234/v1` is the default. Any OpenAI-compatible `/v1/embeddings` you host works. |
| A generation model server | `ask` / `fix` / `review` / `chat` (CLI mode) | LM Studio serving `qwen2.5-14b-instruct`, or a cloud provider key. Not needed in MCP mode — the agent brings its own model. |

## Local models

Skelpr speaks to any OpenAI-compatible server, and expects **two different models for two
different jobs**:

| Job | Model | Used by |
|---|---|---|
| Embeddings | `text-embedding-nomic-embed-text-v1.5` — GGUF, `Q8_0` | `skelpr index` and vector retrieval — needed in **both** modes |
| Generation | `qwen2.5-14b-instruct` | `ask` / `fix` / `review` / `chat` — CLI mode only |

### 1. The embedding model (required)

Non-vector retrieval works without it. Vector search falls back to a deterministic
hashing embedder rather than failing, so a missing embedding server shows up as *quietly
worse recall*, not as an error. Start it before you index.

**LM Studio** (what the default config points at):

1. Install LM Studio from <https://lmstudio.ai>.
2. In the model catalog, search `nomic-embed-text-v1.5` (publisher `nomic-ai`) and
   download the **`Q8_0` GGUF** build — the exact one the default targets:

   | Field | Value |
   |---|---|
   | Model | `nomic-ai/nomic-embed-text-v1.5` |
   | Format | `GGUF` |
   | Quantization | `Q8_0` |
   | Architecture | `nomic-bert` |
   | Domain | `embedding` |
   | Size on disk | ~146 MB |

3. Load the model, then start the local server (**default port 1234**) and confirm it
   answers:

   ```bash
   curl -s http://127.0.0.1:1234/v1/embeddings \
     -H 'Content-Type: application/json' \
     -d '{"input":["hello"],"model":"text-embedding-nomic-embed-text-v1.5@q8_0"}'
   ```

4. Keep the identifier in `.skelpr.yaml` matching what the server advertises. LM Studio
   puts the quantization in the model name, which is where the `@q8_0` suffix comes from:

   ```yaml
   embeddings:
     endpoint: http://127.0.0.1:1234/v1
     model: text-embedding-nomic-embed-text-v1.5@q8_0
   ```

You can also load the model elsewhere — another machine, a GPU box, a vLLM or Ollama
server — by pointing `embeddings.endpoint` at it. `skelpr index` says which side you
landed on:

```text
INFO  Embedding server online at http://127.0.0.1:1234/v1/embeddings (dim=768)
WARNING  No local embedding server reachable at http://127.0.0.1:1234/v1; using hashing fallback
```

**Or use the hosted endpoint — no local embedding server at all.** An activation whose
lease carries the `hosted-embeddings` feature can point `embeddings.endpoint` (or
`SKELPR_EMBEDDINGS_ENDPOINT`) at Skelpr's hosted `nomic-embed-text-v1.5` service. Every
command mints its own short-lived credential automatically — nothing extra to configure:

```bash
export SKELPR_EMBEDDINGS_ENDPOINT=https://embeddings.skelpr.com   # your install's URL
skelpr index    # probes, authenticates, embeds at dim=768
```

Deployment, cost knobs, and measured usage vs. the free tier:
[deploy/embeddings/README.md](deploy/embeddings/README.md).

Because a hosted endpoint comes with a credential, an endpoint that is *down* is treated as
a failure rather than a degradation: `skelpr index` stops instead of writing fallback vectors
into a real-model collection. Queries still answer — lexical, symbol and graph need no model
server, and `skelpr_health` reports the vector backend as `unavailable`.

### 2. The generation model (CLI mode)

```bash
# LM Studio — load qwen2.5-14b-instruct and start the server on port 1234
# vLLM
vllm serve qwen2.5-14b-instruct --dtype auto --max-model-len 32768
# Ollama
ollama serve && ollama pull qwen2.5:14b
```

> ⚙️ Full LM Studio setup steps and the complete `.skelpr.yaml` reference: **[docs/CONFIGURATION.md](docs/CONFIGURATION.md)**

## CLI commands

**Core**

| Command | What it does |
|---|---|
| `skelpr setup` | Start Docker services (Postgres + Qdrant) and build the sandbox image |
| `skelpr init` | Create `.skelpr.yaml` configuration |
| `skelpr index` | Build/refresh hybrid knowledge base |
| `skelpr watch` | Index once, then keep both stores fresh in the background: re-embeds changed/removed files and detects clean branch switches (off by default inside `serve`/MCP — enable with `indexing.watch.enabled` or `SKELPR_AUTO_REINDEX=1`) |
| `skelpr ask` | Ask grounded questions about the repo |
| `skelpr chat` | Interactive loop for ask/fix (no shell quoting needed) |
| `skelpr context` | Export token-optimized context chunks to stdout |
| `skelpr review` | Review a git diff and emit structured findings |
| `skelpr fix` | Diagnose an issue and generate a minimal patch |
| `skelpr validate` | Run configured test/lint/typecheck in sandbox |
| `skelpr serve` | Start the local FastAPI server |
| `skelpr doctor` | Diagnose the install: repository rows, corpus, freshness, backends, agent wiring. Read-only; exits 1 when something needs fixing |

**MCP**

| Command | What it does |
|---|---|
| `skelpr install-mcp` / `skelpr uninstall-mcp` | Configure/remove the MCP server for detected agents |
| `skelpr register-agent` | Register a custom MCP-compatible agent (e.g. Antigravity, Devin) |

**GitHub integration (opt-in)**

| Command | What it does |
|---|---|
| `skelpr github setup` | Configure GitHub PR review automation (manual/automatic modes) |
| `skelpr github status` | Show current GitHub review automation status |

### Troubleshooting: retrieval returns nothing

Searches that come back empty while everything else looks healthy — commands exit 0, the API is up — are
almost always an index problem, not a retrieval-quality one. `skelpr doctor` answers it in one read-only
pass and exits non-zero when something needs fixing:

```bash
skelpr doctor          # only what needs attention
skelpr doctor --verbose # every check, including the passing ones
```

The failure it exists for is a **second repository row for the same checkout** — an index built once
from a relative path (`Path("my-repo")`) sits beside the absolute one, retrieval is answered per row, and
the row your path resolves to may be empty. `doctor` reports both rows and the fix, and never mutates
the database to clean it up:

```
index
  ✗ 1 other repository row(s) describe this checkout: 'my-repo' (this path resolves
    to row #1 at '/srv/checkouts/my-repo')
      → retrieval is answered per row, so searches come back empty from whichever
        path resolved to another one; re-index this repository from its root
        (`skelpr index --full`)
```

Agents see the same summary from `skelpr_health`, so a session does not need a terminal to notice.
Read-only by design: nothing here indexes, repairs or deletes — every finding names the command that
does. Docker and the storage services are reported as warnings when absent, because Skelpr runs
end-to-end without them.

## FAQ

**Do I need Docker?** No. The core runs end-to-end out of the box with in-memory fallbacks. Docker adds sandboxed validation plus Postgres + Qdrant for production-scale indexing.

**Do I need an LLM API key?** CLI mode: yes — a cloud key or a local OpenAI-compatible server. Agent mode: no — the agent brings its own LLM; local embeddings via LM Studio make the whole setup keyless.

**Which languages does it support?** Any language with a tree-sitter grammar (regex fallback for the rest); lexical search is language-agnostic via ripgrep.

**Which agents work out of the box?** Claude Code, Cursor, and Windsurf auto-detect via `skelpr install-mcp`; any MCP-compatible agent (Antigravity, Devin, …) via `skelpr register-agent`.

**How is this different from plain embedding RAG?** RAG ranks by similarity only. Skelpr fuses five signals — lexical, symbol, graph, filename, vector — with deterministic source priority, so exact matches win, every result is `path:line`-cited, and negative queries return a *provable* no.

## Roadmap

- Full cross-backend tenant isolation (Qdrant, filesystem, and sandbox scoped like PostgreSQL RLS)
- More agents pre-registered in `install-mcp`
- Repeat-run the A/B arms to quantify single-run variance (the fix task has scored 84 / 92 / 84 across identical runs)

## Development

```bash
pip install -e ".[dev]"
pytest tests/                                  # run all tests
pytest tests/test_indexing.py tests/test_retrieval.py tests/test_mcp_server.py
```

**Test coverage: 95.10%** of `skelpr` — 9101/9452 statements and 2458/2702 branches, measured with
`pytest --cov=skelpr --cov-report=term-missing`. CI gates on a 60% floor — `--cov-fail-under=60` —
so a patch that quietly stops testing something fails the build rather than passing unnoticed.
This figure and the badge above are rewritten on every push by
`scripts/update_coverage_badge.py`, so neither is ever hand-typed.

- Test the MCP server: `python -c "from skelpr.integrations.mcp_server import skelpr_health; print(skelpr_health())"`, or via the MCP Inspector: `npx -y @modelcontextprotocol/inspector@latest python -m skelpr.integrations.mcp_server` (connection, health, retrieval, symbols, dependencies, and validation verified).
- **Observability** — optional Langfuse tracing for retrieval benchmarking; each `skelpr_get_context` call produces a trace with retrieval metrics, timing, context size, and backend status. See [docs/observability-and-beta-testing.md](docs/observability-and-beta-testing.md).
- **Benchmarking** — an agent-agnostic A/B harness (Antigravity/Cursor) with per-arm artifacts: [tests/benchmarking/README.md](tests/benchmarking/README.md), [docs/BENCHMARK.md](docs/BENCHMARK.md), and the WITH/WITHOUT answers in [docs/comparisons/](docs/comparisons/) (one `COMP_<AGENT>.md` per agent).
- **Plan board** — the shortlist of next work as a checkbox list, with one detail file (why now, what to build, done-when) per item: [NEXT_STEPS/README.md](NEXT_STEPS/README.md).

## Docs

| Doc | Contents |
|---|---|
| [docs/BENCHMARK.md](docs/BENCHMARK.md) | Full benchmark reports + how to reproduce |
| [docs/comparisons/COMP_ANTIGRAVITY.md](docs/comparisons/COMP_ANTIGRAVITY.md) | WITH vs WITHOUT — every task's verbatim answer side by side (one doc per agent) |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Mode diagrams, retrieval engine, fallback hierarchy, extension seam |
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Local model setup + `.skelpr.yaml` reference |
| [docs/MCP_SETUP.md](docs/MCP_SETUP.md) | MCP installation, manual registration, troubleshooting |
| [docs/observability-and-beta-testing.md](docs/observability-and-beta-testing.md) | Langfuse tracing setup |

## Contributing

The repository is private: contributions come from people the vendor has granted access to, not
from the public.

```bash
pip install -e ".[dev]"
python scripts/check.py            # board + benchmark claims + repo hygiene (seconds)
python scripts/check.py --all      # + ruff, mypy, pytest
pytest -m "not slow and not docker and not live"   # fast loop; no Docker or backends needed
```

- **[CONTRIBUTING.md](CONTRIBUTING.md)** — setup, the two commands that matter, PR rules.
- **[docs/CODE_MAP.md](docs/CODE_MAP.md)** — which module does what, plus recipes (add a language, add a retrieval signal, add an MCP tool, add a benchmark task).
- **[ROADMAP.md](ROADMAP.md)** — what is next.

Two rules worth knowing before a PR: **published numbers must be re-derivable from artifacts** (`scripts/check_claims.py`), and **no absolute path from your machine may be committed** (`scripts/check_repo_hygiene.py`; see [docs/HYGIENE.md](docs/HYGIENE.md)).

## Support

Skelpr is sold and supported directly by its vendor: access, seat changes, renewals and bug
reports go back through the contact that issued your token, not a public tracker.

- **Security:** report privately — [SECURITY.md](SECURITY.md) says how.
- **Response expectations:** [SUPPORT.md](SUPPORT.md) · **What is stable:** [docs/STABILITY.md](docs/STABILITY.md)

## License

**Proprietary.** Skelpr 0.1.2 and later are licensed under the [Skelpr End User License
Agreement](LICENSE): running needs an access token, the token is issued to a person, and
activating a machine spends one of its seats.

Versions **0.1.0 and 0.1.1** were published under **Apache-2.0** and remain governed by it —
an irrevocable grant that the later change of license does not touch, and that no withdrawal can
take back. Those two releases have been taken out of the project's distribution; what that does
and does not reach is in [docs/DISTRIBUTION.md](docs/DISTRIBUTION.md),
and the Apache-2.0 text is kept at [LICENSES/Apache-2.0.txt](LICENSES/Apache-2.0.txt).

See [NOTICE](NOTICE) for attribution and
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for the dependencies, the benchmark
corpus and the model output quoted in the docs.

The release process is in [docs/RELEASING.md](docs/RELEASING.md); releases are the
git tags on `main`.
