Documents and PDFs
Knowledge doesn't only live in notes. Reports, slide decks, papers, and spreadsheets sit in the same folders, and until now your AI could see them only as opaque files. As of v0.24, Basic Memory can extract a document's text into a Markdown note that sits next to the original file, so search finds what's inside the document and your AI can read it like any other note.
How it works
Put the file in a project, then import it:
bm import document reports/q3-review.pdf
Basic Memory indexes the project, extracts the file, and writes two notes:
| Note | Path | Purpose |
|---|---|---|
| Extracted text | reports/q3-review.pdf.md | The document's text as Markdown, next to the source file |
| Ingestion run | document-ingestion-runs/<run-id>.md | Provenance: which extractor ran, with what settings, against which bytes |
The original file is never modified. The extracted-text note is an ordinary Markdown file: full-text and semantic search index it, read_note reads it, and you can open it in any editor.
reports/
├── q3-review.pdf # the original, unchanged
└── q3-review.pdf.md # extracted text, searchable
document-ingestion-runs/
└── 748d4356-....md # what produced it
Re-running the import is a no-op while the source file is unchanged. Basic Memory won't overwrite a note you wrote or edited by hand at the sidecar path.
~/Downloads, copy it into the project folder first. Use --project to pick a project other than the default. Full options are in the CLI Reference.Supported formats
| Format | Extension | Install |
|---|---|---|
.pdf | basic-memory[pdf] | |
| Word | .docx | basic-memory[documents] |
| PowerPoint | .pptx | basic-memory[documents] |
| CSV | .csv | Included — no extra needed |
Document extraction is optional so the default install stays small. Add the extras you need:
uv tool install 'basic-memory[pdf,documents]'
pip install 'basic-memory[pdf,documents]'
PDFs are extracted with pdf-inspector; Word and PowerPoint files with Microsoft's markitdown converters. Both run in a separate worker process with time and size limits, so a malformed or huge file can't hang Basic Memory. A CSV becomes a bounded preview — the header and the first 200 rows as a Markdown table — rather than a full dump, and must be valid UTF-8.
What the extracted note looks like
The note's frontmatter records where the text came from:
---
title: q3-review.pdf
type: extracted_text
schema: schema/document-extraction
tags: [document, pdf, generated]
source:
media_type: application/pdf
file_path: reports/q3-review.pdf
checksum: sha256:...
extraction:
engine: firecrawl/pdf-inspector
status: complete
page_count: 12
pages_needing_ocr: []
ingestion:
stage: raw
run_id: 748d4356-...
bm_parse_semantics: false
---
<!-- Page 1 -->
Q3 Business Review
...
type: extracted_textmarks it as derived text. Sidecars written by earlier versions usetype: document; both are valid and Basic Memory never rewrites one into the other.sourceidentifies the exact file and the checksum of the bytes that were extracted.extractionsummarizes the result — status, page counts, and any scanned pages that need OCR. The full per-page map lives on the ingestion-run note, which keeps long PDFs' sidecar frontmatter small.- Page markers (
<!-- Page N -->) keep PDF page boundaries visible in the text.
Extracted text stays graph-quiet
Raw extracted text is searchable, but it doesn't add observations or relations to your knowledge graph — bm_parse_semantics: false. A PDF that happens to contain - [note] ... or [[Something]] won't flood your graph with accidental facts and links.
The one connection every extracted-text note does get is a derived_from relation to its source file. Basic Memory adds it from the note's source frontmatter at index time, so build_context can walk from the text to the original PDF and back. Don't write this relation into the body yourself.
Page citations
bm import document produces the raw extracted text only.When an extracted document is enriched — its raw text turned into structured observations — each observation can cite the PDF page it came from. The citation is written as a Markdown footnote plus a matching sources entry in frontmatter, following the Open Knowledge Format provenance convention:
## Observations
- [fact] Revenue increased 14% quarter over quarter. [^document-page-2]
[^document-page-2]: [PDF page 2](/reports/q3-review.pdf#page=2)
sources:
- id: document-page-2
resource: /reports/q3-review.pdf#page=2
title: q3-review.pdf, p. iv
locator:
page: 2
page_label: iv
page is the physical page in the PDF (the one a viewer jumps to with #page=2); page_label is the optional printed page number. Page numbers are checked against the extraction's page count, and the link is built from the source file's path rather than supplied by an AI, so a citation always points at the real file. Enriched documents turn semantic parsing back on, so their observations join the graph like any other note's.
Other files in your project
Files you don't extract are still part of the project. Images, PDFs, and other non-Markdown files are indexed as file entries you can list, read with read_content, link to, and move. As of v0.24 each one also records its content type and format. Moving one preserves its bytes exactly, and deleting one through Basic Memory removes it from storage.
Metadata filters in search_notes apply to Markdown notes only.

