Sheets

Captain indexes Excel, CSV and TSV files as row bands that carry their header row and their cell coordinates. This page covers how tables are detected, how a workbook is chunked, what a result contains, and the limits.

This is useful for

  • Price lists, rate cards and inventory exports, where a value only means something next to its column name
  • Monthly CSV exports, where a filter on a column narrows to the rows that matter
  • Budget and model workbooks, where a reviewer needs to see how a total was built
  • Reports whose numbers must come from the cells and not from an estimate

What one workbook becomes

Each sheet is scanned for tables. A sheet with a summary block above a data table is two sections. The header row is detected, merged header cells are folded into a composite header of up to four rows, and hidden sheets are included. Each table becomes row bands rendered as markdown tables. The title rows and label-value pairs above a table become one “sheet information” chunk per sheet (row_role: "sheet_header"), so they are indexed once rather than repeated on every band.

How a workbook is chunked

1

Row bands with the header

Tables are cut into row bands of about 1,000 tokens. The header row is written at the top of every band, so a band reads as a table with named columns rather than a list of values.

2

Nothing is dropped

An oversized cell (for example a 20,000-character notes column) is sliced across passages rather than truncated. Cells beyond the detected table width are appended to their row. A blank row ends a table; it does not end the sheet.

3

Cell coordinates

Every chunk carries sheet_name, section, row_start, row_end, col_start, col_end (1-based worksheet coordinates) and columns (the header names). A result exposes them on location. Each column’s first-row value is also stored as a filterable field, so a filter on a column name works like a filter on custom metadata.

4

Formulas and dates

Cells show their cached computed values. Formula text is recovered separately and listed in a Formulas: footer on the bands whose rows contain formulas, with copied-down formulas collapsed to one pattern per range (D2:D40 = B{r}*C{r}). Dates are rendered as ISO 8601 regardless of the display format.

5

Summaries

Each band’s generated summary is given facts computed from the band: the row count, each numeric column’s exact minimum and maximum, columns that are uniform across every row, and the most repeated values with their counts. The summary is restricted to those facts for any range or count, quotes cell values verbatim, and names the subset when it describes one. It does not estimate totals.

6

Pictures

Pictures anchored to cells (a logo, a site photo, a pasted chart image) are described and indexed as their own chunk with row_role: "figure" and the anchor cell range. Native Excel charts are counted but not extracted. Pictures are skipped when mask_pii is on.

Querying workbooks

A large workbook can fill a result page with its own rows. max_chunks_per_document caps how many chunks one document contributes; the freed slots are filled from other documents, so limit still holds. To read a band in context, filter on sheet_name and a row_start range.

Limits

Excel’s own ceilings apply: 1,048,576 rows and 16,384 columns per sheet. A CSV or TSV is read with the delimiter its extension implies; encoding is UTF-8 (with or without a BOM), then Latin-1. A workbook with no tabular data (a template, an empty export) indexes as zero chunks and reports success. Size limits by route are on File Size Limits.

Examples

Goal: return one part number with every supplier’s price labelled by column, from a two-thousand-row price list.

request
{
"query": "PN-20481 unit price",
"limit": 3,
"filter": {
"sheet_name": {
"$eq": "Prices 2026"
}
}
}
result (one item)
{
"text": "| Part | Description | Supplier A | Supplier B | Supplier C |\n|---|---|---|---|---|\n| PN-20481 | 40 mm ball valve, stainless | 41.20 | 39.85 | 44.00 |",
"modality": "spreadsheet",
"location": {
"sheet_name": "Prices 2026",
"row_start": 212,
"row_end": 212,
"col_start": 1,
"col_end": 5
}
}

The header row is part of the band, so each price is labelled by supplier. col_start and col_end give the cells to highlight.

Goal: search one month’s export for the largest refunds in one region, without one file taking the whole result page.

request
{
"query": "largest refunds in March",
"limit": 10,
"filter": {
"region": {
"$eq": "EMEA"
}
},
"max_chunks_per_document": 2
}

region is a column in the export; each column’s first-row value is a filterable field. max_chunks_per_document limits each file to two bands in the result.

Goal: show a reviewer how a total was built. The totals row shows its cached value, and the band’s Formulas: footer shows the pattern.

end of the band's text
| Total | | 412,300 |
Formulas:
C41 = SUM(C2:C40)
D2:D40 = B{r}*C{r}

Formula text is recovered separately from the cached values, so a search for SUM(C2:C40) finds the band.

See Supported File Types for the extension table.

© 2026 Captain