Metadata-Version: 2.5
Name: pinakes
Version: 0.25.0
Summary: A portable, agent-first knowledge base. One directory = one KB.
Project-URL: Homepage, https://github.com/lucagattoni/pinakes
Project-URL: Documentation, https://lucagattoni.github.io/pinakes/
Project-URL: Design, https://github.com/lucagattoni/pinakes/blob/main/docs/DESIGN.md
Author: Luca Gattoni
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: embeddings,knowledge-base,mcp,rag,retrieval,sqlite
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Text Processing :: Indexing
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: jinja2>=3.1
Requires-Dist: mcp>=1.28
Requires-Dist: numpy>=2.0
Requires-Dist: python-ulid>=3.0
Requires-Dist: ruamel-yaml>=0.19
Provides-Extra: claude
Requires-Dist: anthropic>=0.116; extra == 'claude'
Requires-Dist: pypdfium2>=5.12; extra == 'claude'
Provides-Extra: light
Requires-Dist: fastembed>=0.8; extra == 'light'
Provides-Extra: pdf
Requires-Dist: pypdfium2>=5.12; extra == 'pdf'
Provides-Extra: st
Requires-Dist: sentence-transformers>=5.0; extra == 'st'
Description-Content-Type: text/markdown

# Pinakes

**A portable, agent-first knowledge base. One directory = one KB.**

> *The* Pinakes *were Callimachus's catalogue of the Library of Alexandria — the first known index
> of a body of knowledge.*

[![PyPI](https://img.shields.io/pypi/v/pinakes.svg)](https://pypi.org/project/pinakes/)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.13%2B-blue.svg)](https://www.python.org/)
[![Docs](https://img.shields.io/badge/docs-lucagattoni.github.io%2Fpinakes-blue.svg)](https://lucagattoni.github.io/pinakes/)

📖 **[Documentation site](https://lucagattoni.github.io/pinakes/)** — searchable, and the same
files rendered below: **[Guide](docs/GUIDE.md)** · **[CLI](docs/CLI.md)** ·
**[Manifest](docs/MANIFEST.md)** · **[Design](docs/DESIGN.md)** ·
**[What ships today](docs/STATUS.md)**

---

## The idea

A knowledge base is a plain directory you can read, edit, diff, commit and hand to someone:

```
my-kb/
├── pinakes.toml              # manifest: sources, models, chunking, budget
├── docs/                     # SOURCE OF TRUTH — your files, unmodified
│   ├── paper.pdf
│   ├── paper.pdf.pnk.yaml    # sidecar: stable ID, tags, links, provenance
│   ├── notes.md
│   └── notes.md.pnk.yaml
└── .pinakes/                 # generated, disposable, gitignored
    └── index.db              # SQLite: chunks, FTS5, vectors, links
```

Your documents and their metadata are the truth. The index is derived state that can always be
rebuilt. That split is what makes a KB both a **reproducible recipe** and a directory you can move.

## What makes it different

**It costs nothing to run.** Retrieval is BM25 (SQLite FTS5) + local embeddings + local reranking,
fused and scored entirely on your CPU. No API key is needed to search, and re-indexing is free — so
there is never a cost reason not to improve your chunking or swap your embedding model. That the
free path stays free is enforced by a CI gate, not by a promise.

**Reasoning is the caller's, not the KB's.** The MCP tools return ranked, cited evidence.
`pinakes_search → pinakes_get → pinakes_search` *is* a plan-retrieve-read-refine loop, and your agent
already runs it in its own context. Multi-hop reasoning falls out of composable tools rather than a
second agent framework.

**Money is opt-in and bounded by design.** Every paid path is an explicit, enumerated entry point,
and a pre-call reservation makes a hard cap a real ceiling rather than an after-the-fact report.
See [what is actually built](docs/STATUS.md).

**KBs link to each other.** Sidecars carry `pnk://<kb-ulid>/<doc-ulid>` references, so links survive
renames, moves, and being shared with someone else. `pnk links` and the `pinakes_links` tool walk
them — bounded, and a neighbour in another KB is returned but never expanded, because this index
holds that KB's links pointing *here* and not its own. `pnk sync --scan-links` learns what points
back by reading the other KB's committed sidecars, and `pnk link` authors one from the command
line, straight into the source document's own sidecar.

**Your sidecars are yours.** They are read and written through a round-trip parser, so a rewrite
keeps your comments, your quoting and your own key order — and a value is stored as you wrote it:
`country: NO` stays `NO`.

**Its limits are published, not hidden.** No vector tier is sublinear; cross-KB answers will be
capped by how well your KBs are linked; and the confidence heuristic's measured false-confidence rate is
**0.25** — one no-answer question in four still gets a confident answer. A heuristic whose cost is
unmeasured is worse than one whose cost is known.

## Quickstart

```bash
uv add "pinakes[st]"                  # default backend
uv add "pinakes[light]"               # fastembed, no torch
uv add "pinakes[light,pdf]"           # + PDF ingest, free and local
uv add "pinakes[light,pdf,claude]"    # + the two opt-in paid paths: scanned PDFs, and `ask --deep`
```

`[claude]` installs the two paths that can spend money, and neither spends without you asking.
**Transcribing a scanned PDF** takes `--extract=claude-vision` (or a manifest key); **answering a
question** takes `pnk ask --deep`. Both also take a real API key in the environment, under a name
only Pinakes reads. Everything else — search, sync, and `pnk ask` without the flag — is free and
offline.

When you do ask, the whole run is priced before the first call and refused if it would breach any of
the three `[budget]` caps — `per_operation_eur`, `daily_eur` or `monthly_eur`. Raising one and
hitting the next is the discovery path those caps exist to prevent, so a refusal names every window
that binds, not just the first, and prints the manifest edit that would admit the run. Every call is
then reconciled to what it actually cost, and `pnk budget` reports it.

```bash
pnk init my-kb                        # stamp a KB
pnk sync                              # index what changed (git-hook friendly)
pnk search "hybrid retrieval"         # free: BM25 + vector + rerank
pnk ask "how does fusion work?"       # the same evidence, plus what answering would cost
pnk ask "…" --deep                    # ...and this one pays to answer it, under [budget]
pnk doctor                            # environment, coherence, orphans, link coverage
pnk upgrade                           # what your template changed; writes nothing

uvx --from "pinakes[st]" pnk serve    # MCP server, nothing installed
```

⚠️ Two things `pnk init` cannot know, each needing one manifest edit: on a `[light]` install set
`provider = "fastembed"`, and to index PDFs add `"**/*.pdf"` to `[sources] include`. Both are in the
[Guide](docs/GUIDE.md#choosing-a-backend).

**→ [Full guide](docs/GUIDE.md)** — PDFs, filters, calibration, git hooks, MCP setup, troubleshooting.

## Development

```bash
make install    # sync the dev environment (the light extra — CI's minimum leg)
make check      # every gate, stopping at the first failure — run before every commit
make demo       # index the synthetic demo KB
make eval       # golden-set evaluation against the recorded baseline
make corpus     # regenerate the synthetic PDF corpus in place
make pdf-eval   # extraction-quality baseline + floor-drift check (needs [pdf])
make budget     # the demo KB's spend ledger (free: it only reads)
make docs       # build the documentation site (--strict — exactly what CI runs)
make docs-serve # preview it at http://127.0.0.1:8000 with live reload
make help       # all targets
```

Every target wraps the command CI actually runs, so green locally means green on the runner. Note
that `make check` formats Python **inside Markdown fences** too — a docs-only change can fail it.

Conventions are in [`CLAUDE.md`](CLAUDE.md), the increment workflow in
[`docs/BUILDING.md`](docs/BUILDING.md); how the docs are organised —
and which file to edit when you land a feature — is in [`docs/README.md`](docs/README.md).
[`docs/VERIFICATION.md`](docs/VERIFICATION.md) maps every promise this project makes to the test
that holds it, and a test asserts every one of those tests exists.

## Your data stays yours

This repository contains the **engine only**. Real knowledge bases live outside it. The only KBs
here are two small synthetic corpora — an archive and a partner museum that transacts with it —
used for tests, retrieval benchmarking and cross-KB linking, and the only other committed content
is `tests/pdf-corpus/` — PDFs generated from scratch by a committed script to exercise hard
extraction cases. None of it was harvested from anywhere; no real-world document is committed
here.

`pnk init` ships a `.gitignore` covering `.pinakes/`, so your index — and your spend ledger — never
leaves your machine. Note that publishing a KB repo publishes `docs/` *and* every sidecar: titles,
tags and provenance URLs included.

## Licence

[Apache-2.0](LICENSE).
