Skip to main content
Most fund-ops runbooks start the same way: a file lands in storage (an invoice, a bank statement, a rent roll, a trial balance) and the runbook needs to turn its bytes into something it can reason about. ntro.capabilities.files does that turn.

Install

The capability is bundled with the workflow extra — runbooks always have it.

The API

One public coroutine:
Returns a CellGrid-shaped object with two key surfaces: Both fields are populated by both formats. The downstream AI extraction step typically reads plain_text and passes cells as structured_context so the model can disambiguate when layout matters.

PDF parsing — format="pdf"

Backed by pdfplumber. Best for:
  • Scanned-and-OCR’d documents (invoices, statements, contracts)
  • Form-style documents with key-value pairs
  • Documents with tables that have visible borders
Lifted from the document-ingest runbook:
Two things to notice:
  • The bytes come from the tenant data plane (Postgres), not the activity payload. Signals carry only the document_ref so payloads stay small.
  • Both grid.cells and grid.plain_text flow into the RawDocument so the next step (AI extraction) has both.

Excel parsing — format="xlsx"

Backed by openpyxl. Best for:
  • Trial balances exported from Xero / SAP / Sage
  • Investor registers, capital call schedules, NAV templates
  • Anything where preserving sheet / cell coordinates matters
Lifted from the nav-monthly-journals runbook:
The pattern is the same: parse → feed the LLM both the prose and the structured cells → produce a typed model.

Choosing between cells and plain_text

When you hand the result to AI extraction, passing both as in the examples above is the safe default — it costs nothing and gives the model the most signal.

Private AI

The natural next step — ai.extract() consumes what files.parse() produces.

Data

Where parsed documents typically come from (storage.read or the data plane).