Read Records from a Spreadsheet
Reads the records tab of an uploaded workbook — the header row it identifies, the context lines sitting above the table, and the data rows beneath it, each with its sheet row number.
Overview
Real spreadsheets are not clean data files. The first row is a merged title cell with the project name. Row 2 is blank. Rows 3 and 4 hold the job number and the inspection date. The actual header sits on row 6. Then come the line items, with a couple of subtotal rows in the middle, a note in the margin column, and three empty rows at the bottom where somebody deleted content but not the rows.
Any importer that assumes row 1 is the header and every row below it is a record will produce garbage from that file — and it will do it silently. This tool takes the opposite approach. It works out which row is the header, returns the lines above it as context, and hands back the rows beneath it without deciding which of them count.
No row is dropped for looking like decoration. The subtotal row comes back. The section divider comes back. The note in the margin column comes back. Which rows are real line items and which are furniture is judged by the agent reading the values, not by a fixed importer rule that cannot tell a subtotal from a very cheap line item.
What It Does
| Capability | What it means for you |
|---|---|
| Header row identified | Column names come from the row the tool picks out as the header, not from row 1 |
| Context lines preserved | The project name, job number and dates that sit above the table are returned as context, not discarded as noise |
| Rows in sheet order | Each row comes back with its own sheet row number, which is how a chosen row is referred to afterwards |
| No decoration filtering | Subtotals, section dividers and one-cell notes are returned rather than guessed at |
| Judgement left to the agent | Relevance is decided by something that can read the row, not by a fixed importer rule |
When the Agent Chooses This Tool
This tool belongs to one workflow: coating QA inspection packages. The agents that assemble appraisal reports and pre-bid submissions do not have it.
Inside that workflow the sequence is fixed. The agent lists the package's attachments once, picks out the spreadsheet among them, and reads its records. If no spreadsheet is attached, it stops and asks for one.
Reading is not a formality, because the row count is not the answer:
- It picks out the real data rows. A 40-row sheet does not mean 40 forms. The agent is told to exclude trailing totals, repeated header rows and section-title rows — and to apply any narrowing in the user's own request, like "only entries after 5/1" or "skip stripe coats", by reading the values.
- It reads the context lines. The lines above the table are where a vessel or project name lives, and the package takes its name from them. Those same lines are attached to every row's data when the forms are filled, so a value that appears once at the top of the sheet lands on every page.
- It works out what the columns mean. Nothing about the columns is configured anywhere. The agent is told to read the values to understand what each heading refers to, so there is no column-mapping file to write.
Once the rows are chosen, one form is created per row by creating one form per spreadsheet row.
Inputs and Outputs
Takes: an Excel workbook already attached to the same package, read at the records tab named by the package's configuration.
Returns: the context lines found above the table, the header row it identified, and the data rows in sheet order, each with its sheet row number.
Nothing is written. No sections are created, no forms are filled, and the spreadsheet itself is untouched.
Example
A coating inspector uploads the master workbook for a hull job. The records tab looks like this:
- Row 1: YC BARGE — COATING APPLICATION LOG
- Row 2: blank
- Row 3: Vessel / Hull: YC Barge
- Row 4: Inspector: M. Alvarez
- Row 6: headers — Date, Area, Coat, DFT, RH %, Notes
- Rows 7 to 34: 24 application events, a STRIPE COATS divider on row 19, a TOTAL row on row 34, and two rows somebody emptied but did not delete
Row 6 is taken as the header, because it carries more text than any other row near the top of the sheet. Rows 1, 3 and 4 come back as context lines; row 2 contributes nothing. The two emptied rows are not returned at all. Twenty-six rows come back, including the divider — one cell with a label in it and nothing else — and the TOTAL row.
The agent drops those two, leaving 24, and one page is created per remaining row. The vessel name from the context lines becomes the package's name and is attached to every row's data.
Nobody configured a column map, a header offset or a skip rule.
Limits
- One records tab. The tool reads the single tab named by the package's configuration. It is not a workbook browser and does not roam across the other sheets in the file.
- The header has to be near the top, and it has to look like one. The header is taken to be the row with the most text cells among the first twenty rows, and it needs at least three of them. A header further down than row twenty is not found at all, and the read fails rather than returning rows. Where the widest run of text near the top of a sheet is a data row — long free-text notes, say — that data row's values are taken as the column names and the real header comes back as a context line.
- Only the first 300 rows come back. The count reported alongside them is the true number of data rows on the sheet, so a 400-row sheet reports 400 and returns 300. Nothing can ask for the rest.
- Values are reformatted on the way out. Decimals are rounded to two places, so a 0.001 reading comes back as 0. A large value that carries a decimal fraction comes back in scientific notation; whole numbers are returned unchanged however large. Dates and times are rewritten in US month/day order. Runs of spaces inside a cell collapse to one.
- Empty cells and empty rows are not reported. A row comes back carrying only the cells that had something in them, and a row with nothing in it at all is not returned. Where a value is merged down a block of rows, only the first row of the block carries it. A cell holding a formula comes back with the value the file last saved for it — a workbook written by another program and never opened in Excel has no saved value, and those cells are simply absent.
- One header row, whatever the layout. Stacked two-line headings, side-by-side tables and merged header cells are not reconstructed. One row supplies the column names for the whole sheet, a second heading row is returned as either context or data, and any column past the last heading is named by its spreadsheet letter.
- Values, not calculations. The tool does not recompute, reconcile or validate anything, and it will not tell you a total is wrong.
- It reads; it does not act. No sections are created here. That is a separate, deliberate step, so a bad read never quietly produces 200 forms.
- Modern Excel workbooks only. An .xlsx or .xlsm file reads. A legacy .xls file and a CSV are accepted as attachments and then fail to read.
FAQ
Do I need to clean up my spreadsheet first?
No, with one condition. Title rows, project details above the header and subtotal lines are all normal and all handled, so you do not have to reformat a working file into a clean data export. What does have to hold is the header: it needs to sit within the first twenty rows and to be the widest run of text in that part of the sheet.
Does the header have to be the first row?
No, but it does have to be near the top. The header is taken to be the row with the most text cells among the first twenty, and the lines above it are returned as context rather than discarded. Those context lines are often exactly where the job number and project name live.
Why return every row instead of filtering out the junk?
Because filtering by rule is where importers go wrong. A rule that drops rows with a missing value in one column will silently drop legitimate records. No row is dropped here for looking like decoration — subtotals, dividers and one-cell notes all come back — which lets the agent judge each row in context, and then say which rows it excluded and why.
Do I have to map spreadsheet columns to form fields?
No. Nothing about the columns is configured anywhere. The agent is told to read the column headings together with the values underneath them to work out what each column holds, so no mapping file is written first.
Does reading the spreadsheet create any forms?
No. Reading and creating are separate steps on purpose. Producing one form per row is a distinct action the agent takes only after it has read the rows and decided which ones are real.