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

# Extract Archive File

> Extract exactly one file from a ZIP archive and store it as a run output file. Downstream steps can pass the whole extract output into Parse, Vision, or another archive step.

`transform.archive-extract` pulls **exactly one** archive-relative path out of a
ZIP and stores the bytes as a run output file. Downstream file steps consume
the **whole step output** — `{{ steps.extract.output }}` — not a nested
`fileId` field.

ZIP is the only accepted archive format in this version. A nested ZIP is stored
as `application/zip` and can be passed into [List Archive](/steps/transform/archive-list)
or another extract step. It is not unpacked automatically.

Pair this step with list + foreach (or parallel\_map) when you need every
matching file:

```yaml theme={null}
inputs:
  - name: bundle
    type: file

steps:
  - name: list
    type: transform.archive-list
    with:
      archive: "{{ input.bundle }}"

  - name: each
    type: control.foreach
    items: "{{ steps.list.output.entries }}"
    as: item
    steps:
      - name: extract
        type: transform.archive-extract
        with:
          archive: "{{ input.bundle }}"
          path: "{{ item.path }}"
      - name: parse
        type: ai.parse
        with:
          input: "{{ steps.extract.output }}"
```

Inside the loop, `{{ steps.extract.output }}` is the file from **this**
iteration. After the loop finishes, the foreach output is an array of results —
it is not itself a file handle.

A nested ZIP stays a ZIP. Extract it, then list or search the extract output:

```yaml theme={null}
  - name: extract_packet
    type: transform.archive-extract
    with:
      archive: "{{ input.bundle }}"
      path: nested/packet.zip
  - name: list_inner
    type: transform.archive-list
    with:
      archive: "{{ steps.extract_packet.output }}"
```

`transform.script` JSON that copies a `fileId` is not treated as a trusted
file. Only outputs from file-producing steps (including this one) rehydrate
after a run resumes.

Encrypted members are rejected. A nested ZIP stays a ZIP file — pass
`{{ steps.extract.output }}` into [List Archive](/steps/transform/archive-list)
or [Search Files](/steps/ai/search-files). Git-backed Agents do not run this
step. Hosted vs headless vs on-prem ceilings: [Upload files](/guides/upload-files).

## Limits

Each extraction is bounded at three layers:

1. **Per entry** — 64 MiB uncompressed and 64 MiB compressed for the single
   path this step reads.
2. **Per ZIP reader** — 512 MiB of actual inflated bytes summed across reads
   on that reader instance. Archive extract opens a reader, reads one entry,
   and closes it.
3. **Process-wide concurrent budget** — 512 MiB of *declared* uncompressed
   size across in-flight extracts in the same worker process. Extra extracts
   wait until inflating ones finish. Override with
   `ZIP_PROCESS_INFLATION_BUDGET_BYTES`. This is a live memory admission
   cap, not a persisted per-run quota: a long run can still extract more
   than 512 MiB in total, just not all at once.

`control.parallel_map` concurrency is still capped at 50, but those workers
share the process budget, so a map of 50 large files cannot inflate
50 × 64 MiB simultaneously.

| Limit                             | Value                                        |
| --------------------------------- | -------------------------------------------- |
| Archive format                    | ZIP only                                     |
| Files extracted per step          | 1                                            |
| Max inflated size per entry       | 64 MiB                                       |
| Max compressed size per entry     | 64 MiB                                       |
| Max inflated bytes per ZIP reader | 512 MiB                                      |
| Process-wide concurrent inflation | 512 MiB declared uncompressed (configurable) |
| `parallel_map` max concurrency    | 50                                           |

## Configuration

Configuration goes inside the step's `with:` block.

<ParamField path="archive" type="string" required>
  Template expression or file reference for the ZIP archive. ZIP is the only accepted format in this version.
</ParamField>

<ParamField path="path" type="string" required>
  Archive-relative path of the single file to extract, for example \{\{ item.path }} from a prior archive-list step.
</ParamField>

## Output

<ResponseField path="fileId" type="string" required>
  File ID from the files table
</ResponseField>

<ResponseField path="path" type="string" required>
  Normalized archive-relative path that was extracted
</ResponseField>

<ResponseField path="filename" type="string" required>
  Basename of the extracted file
</ResponseField>

<ResponseField path="mimeType" type="string" required>
  Detected MIME type of the extracted file
</ResponseField>

<ResponseField path="size" type="integer" required>
  Uncompressed size in bytes
</ResponseField>
