> ## Documentation Index
> Fetch the complete documentation index at: https://docs.riggery.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Files extract

> Read tables from a file on this Instance. The step returns a summary; import uses the same File id.

**Files extract** reads tables from one file already stored on this Instance (upload, Telegram, mail, webhook, or an Agent). Catalog line: structure-extract tables from an artifact.

**View results** is a markdown **summary**, not every row. Tables stay with the file. Put them in State with [State import from file](/graph/tools/state-import-from-file) and the **same File id**.

Inbound CSV/XLSX can become State on the Trigger instead: [Inbound files](/graph/triggers#inbound-files).

<h2 id="how">
  How it runs
</h2>

<Steps>
  <Step title="Resolve File id">
    One opaque id. See [File id](#file-id).
  </Step>

  <Step title="Find tables">
    CSV and XLSX: one table per sheet, in this step. PDF: Docling; the step waits up to **Wait ms**.
  </Step>

  <Step title="Write the summary">
    Status, counts, optional warning/error, a short **Sample**, optional **Document text**. Same **File id** later reuses the extract. If the summary is still queued or running, run again or raise **Wait ms**.
  </Step>
</Steps>

<h2 id="input">
  Input
</h2>

Inspector **Settings**. Empty-field rules for the Graph: [Previous nodes](/graph/previous-nodes). This inspector has no **Insert value**; you can type `{{…}}`.

On an Agent Tool, both fields can be **Agent decides** or **Fixed**. On a Graph node you type the values.

| Field       | Required | Empty            | Notes                                                                                           |
| ----------- | -------- | ---------------- | ----------------------------------------------------------------------------------------------- |
| **File id** | Yes      | Fail             | Opaque Instance file id. Not a filename. [Details](#file-id).                                   |
| **Wait ms** | No       | Default: `90000` | How long to wait while PDF extract is still running. 1000–300000. CSV/XLSX finish in this step. |

<h3 id="file-id">
  File id
</h3>

Empty does **not** use the previous node's Result — this node fails. Connecting [Files list](/graph/tools/files-list) without filling this field still fails: list Result is a catalog, not one id.

Use the Instance file id, the `id` in a [Photos / Files](/graph/previous-nodes#attachments) array, or `artifactId` in this step's own summary. Not the filename (`rates.csv`), not **Message: Files** / **Photos** as a JSON array, not this step's Result markdown.

**Agent decides:** the model can take the id from Files list or this turn's attachments. **Fixed** / Graph: paste one id, or a placeholder that expands to **only** that id (for example `{{Input}}` when Test input is the id).

<h2 id="output">
  Output
</h2>

On the next node, **Previous nodes** lists **`Files extract`: Result** (`{{Files extract.text}}` while the name is unique).

| Output | In menu | Type          | Next node gets                                                                                                                                       |
| ------ | ------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Result | Yes     | Markdown text | The summary.                                                                                                                                         |
| Tables | No      | —             | Kept with the file. [State import from file](/graph/tools/state-import-from-file) reads them via the same **File id**, not `{{Files extract.text}}`. |

```md theme={null}
## Extract ready

- artifactId: cmtzo4vku002vaxpvc1p9irxo
- name: "rates.csv"
- engine: tabular
- tables: 1
- rows: 42
- markdownChars: 0

Next: state.import_from_file with artifactId=cmtzo4vku002vaxpvc1p9irxo and a collection name.

### Sample
```

`engine` is `tabular` (CSV/XLSX) or `docling` (PDF).

| Result starts with              | Meaning                                                                       |
| ------------------------------- | ----------------------------------------------------------------------------- |
| `## Extract ready`              | Tables are with the file. Import uses `artifactId`.                           |
| `## Extract queued` / `running` | Still working; call again with the same id, or raise **Wait ms**.             |
| `## Extract failed`             | Line `error:`. Fix the file and run again.                                    |
| **No tables found**             | Prose: [Memory upload](/graph/tools/memory-upload). Do not invent State rows. |

**Document text** is non-table prose in the summary. Read it before mapping records. **Sample** is a few rows per table, same column names import will write — do not copy them into [State upsert](/graph/tools/state-upsert).

<h2 id="next">
  After this step
</h2>

**Files extract** → **State import from file** (**Collection**, **Replace collection**). Journey: [Tables into State](/journeys/tables).
