Skip to content

feat(index): multimodal PDF ingest behind opt-in flag (bo-j5r0)#41

Merged
scbrown merged 2 commits into
mainfrom
feat/multimodal-pdf-ingest
Jun 30, 2026
Merged

feat(index): multimodal PDF ingest behind opt-in flag (bo-j5r0)#41
scbrown merged 2 commits into
mainfrom
feat/multimodal-pdf-ingest

Conversation

@scbrown

@scbrown scbrown commented Jun 30, 2026

Copy link
Copy Markdown
Owner

What

Implements the PDF half of bo-j5r0 (multimodal ingest, aegis-1p0 Gap 2 / graphify parity). Opt-in [index] multimodal flag makes bobbin index also walk **/*.pdf, extract text via the pure-Rust pdf-extract crate, and chunk it like a plain-text doc (language = "pdf") — so runbooks, design PDFs, and specs become searchable and graph-extractable.

Why scoped to PDF

The handoff explicitly authorized splitting: "PDF (simpler, pure-Rust) from image-vision (needs LLM)… PDF alone may satisfy the core AC." Bobbin has no chat/vision provider path today (only ONNX/OpenAI-compatible embeddings), so image captioning requires a whole new LLM subsystem. src/index/multimodal.rs is the seam where that second extractor slots in — tracked as a follow-up bead.

AC status

  • bobbin index picks up .pdf behind a config flag
  • ✅ extraction verified against a committed minimal-PDF fixture (text round-trips)
  • ⏳ captioned-image search → follow-up (needs vision provider)

Design

  • Off by default — default dependency/behavior profile unchanged.
  • Single knob: setting the flag auto-injects **/*.pdf into the walk (no manual include edit).
  • read_indexable_content helper routes both index read sites (hash-check + parse); non-PDF path is byte-for-byte the old read_to_string.
  • Image-only / encrypted PDFs yield no text → skipped like empty files.

Tests

cargo test --bin bobbin: 894 passed. New: PDF extraction from fixture, extension detection (case-insensitive), unsupported-ext rejection, flag-gates-walk on/off. Clippy clean (no new warnings).

🤖 Generated with Claude Code

scbrown and others added 2 commits June 29, 2026 21:05
Adds an opt-in `[index] multimodal` flag. When enabled, `bobbin index` also
walks `**/*.pdf`, extracts text via the pure-Rust `pdf-extract` crate (no
Python / native toolchain), and chunks it like a plain-text document tagged
`language = "pdf"` — making runbooks, design docs, and specs searchable.

Off by default, so the default dependency/behavior profile is unchanged. PDFs
that yield no text (image-only / encrypted) are skipped like empty files.

Image captioning (vision LLM) is intentionally out of scope: bobbin has no
chat/vision provider path yet. `src/index/multimodal.rs` is the seam where that
second extractor will slot in; tracked as a follow-up bead.

- src/index/multimodal.rs: extractor (is_multimodal_file, extract_text) + tests
- cli/index.rs: read_indexable_content helper at both read sites; auto-inject
  `**/*.pdf` into the walk when the flag is set
- config.rs: IndexConfig.multimodal (default false)
- parser.rs: detect_language recognizes .pdf -> line-chunked "pdf"
- tests/fixtures/sample.pdf: minimal valid PDF for extraction test
- docs + CHANGELOG

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CG47xMt5cR8EQGk26Ze64u
Vale Style check flagged 'multimodal'/'Multimodal', 'PDFs', and 'runbooks' in
docs/book/src/config/index.md as spelling errors. Add them to the Bobbin
vocabulary accept-list (proper terms, not bypasses): [Mm]ultimodal covers both
cases per the existing [Hh]eatmap idiom.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7b5eTqAZrisQN6NJ4Kn2z
@scbrown
scbrown merged commit b2a32df into main Jun 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant