Metadata-Version: 2.4
Name: dirsql-plugin-embeddings
Version: 0.1.1
Summary: First-party dirsql plugin: semantic search via an OpenAI-compatible embeddings endpoint.
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# dirsql-plugin-embeddings

A first-party [`dirsql`](https://github.com/thekevinscott/dirsql) plugin that
adds **semantic search** over a directory of Markdown files. It is the worked
implementation behind the [Search documents by
meaning](https://thekevinscott.github.io/dirsql/howto/search-by-meaning) how-to,
swapping that guide's local `model2vec` model for any OpenAI-compatible
`/v1/embeddings` endpoint.

```sh
uvx --with dirsql-plugin-embeddings dirsql
```

Deliberately minimal (v0.1): one embedding provider shape, one table, no
chunking, no config surface beyond three environment variables.

## How it works

The plugin ships a `dirsql.toml` fragment that dirsql discovers when the package
is installed alongside it. The fragment declares:

- the [`sqlite-vec`](https://github.com/asg017/sqlite-vec) extension, for
  `vec_distance_cosine()`;
- a `documents` table whose `on-file` hook embeds each `**/*.md` file into a
  TEXT `embedding` column;
- a `pre-query` hook that embeds the incoming question and emits the
  nearest-neighbor SQL.

Both hooks are console scripts that call the same embedder.

## Configuration

The embedder reads three environment variables (point them at any hosted or
self-managed OpenAI-compatible inference server):

| Variable | Meaning |
|---|---|
| `DIRSQL_EMBEDDINGS_BASE_URL` | Base URL; `/v1/embeddings` is appended. |
| `DIRSQL_EMBEDDINGS_MODEL` | Model name sent in the request. |
| `DIRSQL_EMBEDDINGS_API_KEY` | Bearer token for `Authorization`. |

## Console scripts

| Script | Hook | Input | Output |
|---|---|---|---|
| `dirsql-embeddings-on-file` | `on-file` | a file's absolute path (`argv[1]`) | one-line JSON row array with `path`, `text`, `embedding` |
| `dirsql-embeddings-pre-query` | `pre-query` | a raw request body (`argv[1]`) | nearest-neighbor SQL over `documents` |

`pre-query` accepts both a verbatim server body (`{"q": ...}`) and the CLI
`query` subcommand's `{"sql": <arg>}` wrapper, so `dirsql query '{"q": ...}'` and
a real `POST /query` both work.

## Tests

Three tiers, per the dirsql testing conventions:

- **unit** (colocated, mocked seams) — `src/dirsql_plugin_embeddings/*_test.py`
- **integration** (`tests/integration/`) — each console script as a real
  subprocess against a local stub `/v1/embeddings` server
- **e2e** (`tests/e2e/`) — the full loop through the real launcher + `dirsql`
  binary + `sqlite-vec`, nothing mocked but the embedding endpoint
