From asta-tools
Build a searchable Asta document index from a collection of local PDF files. Use when the user asks to "index these PDFs", "put these PDFs into an Asta index", "index these PDFs using Asta", "build a local paper index", "make these PDFs searchable", or "create an index from these papers".
How this skill is triggered — by the user, by Claude, or both
Slash command
/asta-tools:local-paper-indexThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build a searchable Asta document index from a collection of local PDF files. Each PDF is converted to markdown, split into ~2000-character chunks, and written as documents to an asta-documents YAML index — enabling semantic search across the full text of the collection.
Build a searchable Asta document index from a collection of local PDF files. Each PDF is converted to markdown, split into ~2000-character chunks, and written as documents to an asta-documents YAML index — enabling semantic search across the full text of the collection.
This skill includes standalone scripts in the assets/ directory:
| Script | Purpose |
|---|---|
assets/extract-pdfs.sh | Convert PDFs to markdown via asta pdf-extraction remote |
assets/chunk-and-index.py | Chunk markdown files and write the YAML index directly |
assets/warm-cache.sh | Run an initial search to build the search cache |
Locate the assets directory relative to this skill file. The scripts are self-contained and can be copied to the working directory or run in place.
Before starting, ask the user for four things:
my-papers, cs-reading-list).Suggest a directory layout where the PDFs and markdown live as siblings under a common parent, with the index file alongside them. For example, if the PDFs are at /data/papers/pdfs/:
/data/papers/ # DATASET_ROOT — parent of everything
├── pdfs/ # PDF_DIR (user already has this)
├── markdown/ # MARKDOWN_DIR (suggested: sibling of pdfs/)
│ ├── paper1.md # without --images: flat .md files
│ ├── paper2.md
│ ├── paper3/ # with --images: per-PDF subdirectories
│ │ ├── paper3.md
│ │ └── img-0.jpeg
│ └── ...
└── index.yaml # INDEX_PATH (auto-created here)
This layout matters because the index stores relative paths to the markdown files. Keeping everything under one root makes the index portable and git-friendly.
Key rules for the suggestion:
.asta.DATASET_ROOT is the parent directory that contains both PDF_DIR and MARKDOWN_DIR.DATASET_ROOT/index.yaml./home/user/research/pdfs, suggest /home/user/research/markdown and /home/user/research/index.yaml.Once the user confirms (or provides their own paths), set these variables:
PDF_DIR="/data/papers/pdfs" # user-provided
MARKDOWN_DIR="/data/papers/markdown" # user-confirmed
DATASET_ROOT="/data/papers" # parent of both
INDEX_PATH="$DATASET_ROOT/index.yaml" # derived
COLLECTION="my-papers" # user-chosen
IMAGES=false # true if user wants images
PDF_COUNT=$(find "$PDF_DIR" -name "*.pdf" -type f | wc -l)
TOTAL_SIZE=$(find "$PDF_DIR" -name "*.pdf" -type f -exec du -ch {} + | tail -1 | awk '{print $1}')
echo "Found $PDF_COUNT PDFs ($TOTAL_SIZE total)"
Present this estimate to the user before proceeding:
| Metric | Estimate |
|---|---|
| PDFs found | N files |
| Total size on disk | X MB |
| Extraction time | ~2-5 min per 10-page PDF (remote API); faster with olmocr for batches >20 |
| Chunking + indexing | ~1-2 seconds per PDF |
| Index storage | ~2-3x the extracted text size (markdown files + YAML with chunk text) |
| Cache warm-up | 5-30 seconds (one-time, after indexing) |
| Total estimated time | Dominated by extraction: roughly N_papers x 3 min |
Ask the user to confirm before starting, especially for large collections (>20 PDFs).
# Without images (flat layout: markdown/paper.md)
bash /path/to/assets/extract-pdfs.sh "$PDF_DIR" "$MARKDOWN_DIR"
# With images (per-PDF subdirectories: markdown/paper/paper.md + images)
bash /path/to/assets/extract-pdfs.sh --images "$PDF_DIR" "$MARKDOWN_DIR"
Pass --images only if the user opted in during Step 0. When --images is used, each PDF gets its own subdirectory under MARKDOWN_DIR to avoid image filename collisions across PDFs. The chunking script in Step 3 handles both layouts automatically.
The script:
For large batches (>20 PDFs), asta pdf-extraction olmocr with --workers is significantly faster. See the pdf-extraction skill for details.
uv run --with pyyaml python3 /path/to/assets/chunk-and-index.py "$COLLECTION" "$MARKDOWN_DIR" --index-path "$INDEX_PATH" --pdf-dir "$PDF_DIR"
The --index-path argument is required. The script:
url field — making the index portable across machines. The indexed document is the markdown: its url points at the .md file.url; safe to re-run).md by iterating --pdf-dir and matching on basename (the per-PDF subdirectory name, or the flat file stem) — it finds the PDF actually on disk rather than assuming a filename. A .md with no matching PDF is indexed without a source_pdf and warned about.extra): collection, plus source_pdf (a relative/file:// pointer to the upstream PDF) only when --pdf-dir is given and a matching PDF is foundchunk_index, total_chunks, chunk_chars, chunk_offset, file_chars (in extra)<collection-name>, plus pdf-index for PDF-derived markdown or md-index for raw markdownOptions:
--chunk-size 2000 — adjust chunk size (default 2000 chars)--pdf-dir "$PDF_DIR" — directory of upstream source PDFs. Omit it when indexing authored markdown (see Indexing raw markdown below).bash /path/to/assets/warm-cache.sh "$DATASET_ROOT"
The argument is required:
$DATASET_ROOT — the root directory containing index.yamlThis step is required. The first search after indexing builds the internal BM25 + embedding indexes. Without warming, the user's first real search will be unexpectedly slow.
asta documents --root "$DATASET_ROOT" list --tags="$COLLECTION"
asta documents --root "$DATASET_ROOT" show
Tell the user:
DATASET_ROOT pathINDEX_PATHasta documents --root "$DATASET_ROOT" search --summary="query" --tags="COLLECTION"After building, search across all indexed PDFs:
# Semantic search within the collection
asta documents --root "$DATASET_ROOT" search --summary="neural network architecture" --tags="my-papers"
# With relevance scores
asta documents --root "$DATASET_ROOT" search --summary="attention mechanism" --tags="my-papers" --show-scores
# Filter by source PDF
asta documents --root "$DATASET_ROOT" search --extra=".source_pdf contains some-paper"
# List all documents in the collection
asta documents --root "$DATASET_ROOT" list --tags="my-papers"
If your corpus is already markdown (authored .md docs, exported notes, an
investigation record, a wiki), there is nothing to extract — skip Steps 1–2 and
point the chunker straight at the markdown directory. Just omit --pdf-dir:
COLLECTION="my-notes"
MARKDOWN_DIR="/data/notes" # a tree of .md files (rglob, nested OK)
INDEX_PATH="/data/notes/index.yaml"
uv run --with pyyaml python3 /path/to/assets/chunk-and-index.py \
"$COLLECTION" "$MARKDOWN_DIR" --index-path "$INDEX_PATH"
bash /path/to/assets/warm-cache.sh "$(dirname "$INDEX_PATH")"
asta documents --root "$(dirname "$INDEX_PATH")" search \
--summary="your query" --tags="$COLLECTION" --show-scores
The markdown is the source: each document's url points at the .md, the
secondary tag is md-index, and extra.source_pdf is absent (there is no
upstream PDF). Chunking, relative-path URLs, and resumability are identical to
the PDF path — the only difference between the two is whether extra.source_pdf
is present.
| Collection size | Approx. index size | Approx. markdown size |
|---|---|---|
| 10 PDFs (~10 pp each) | 2-5 MB | 1-3 MB |
| 50 PDFs (~10 pp each) | 10-25 MB | 5-15 MB |
| 100 PDFs (~10 pp each) | 20-50 MB | 10-30 MB |
Total storage is roughly 2-3x the extracted text (markdown files + index YAML with chunk text in the summary field).
| Stage | Per PDF | Notes |
|---|---|---|
| Extraction (remote) | 2-5 min / 10 pages | API-bound; 50-page limit per call |
| Extraction (olmocr) | 10-20 sec / page, parallel | Better for >20 PDFs |
| Chunking + indexing | 1-2 seconds | Single YAML write, fast |
| Cache warming | 5-30 seconds total | One-time after indexing |
asta documents search --summary=... builds the search index. Always run the warm-cache script after indexing.index.yaml first.pyyaml. Install with pip install pyyaml or uv pip install pyyaml if not available.markdown/paper.md) so the dataset is portable. This requires the markdown directory to be under the same directory as the index file.npx claudepluginhub allenai/asta-plugins --plugin asta-toolsLocal document metadata index for files used by Asta skills and tools. Use this skill when the user asks to store a document "in Asta" or retrieve "from Asta". Use it when the user references an "Asta document" or anything with an `asta://` URI.
Indexes PDF documents with LightRAG, extracts text via PyMuPDF, builds embeddings and knowledge graphs, enables hybrid semantic searches with citations for document Q&A.
Ingests PDF datasheets or reference manuals into the embedded docs search index via ingest_docs tool. Reports chunks ingested and tables found.