STEP_SCHEMAS in @eigenpal/types, so they always
match what the engine actually accepts and returns.
Steps fall into four categories, see Workflows for how
they fit together.
Full catalog
AI steps
| Step | Type | Summary |
|---|---|---|
| Parse Document | ai.parse | Extract text from documents (PDF, DOCX, images) using native extraction, OCR, or vision models |
| Extract Data | ai.extract | Extract structured data from text using AI with a JSON schema |
| Split Document | ai.split | Split a parsed document into named sections using an LLM. Consumes ai.parse output; emits per-section page ranges and text ready for downstream ai.extract via control.parallel_map. |
| Separate Documents | ai.segment | Separate a concatenated batch (one big scan) into typed document instances using an LLM. Consumes ai.parse output and a type taxonomy; discovers an unknown number of documents in any order and emits per-document page ranges + text + type, ready for type-specific ai.extract via control.parallel_map. The inverse of ai.split. |
| Classify | ai.classify | Classify a document or text into one of a fixed label set using an LLM. Output exposes the picked label (constrained to the configured names), a coarse confidence, and a short justification. Pair with control.fail to reject documents that match an undesired label. |
| Label Pages | ai.classify-pages | Assign zero or more labels to each page independently (multi-label) using an LLM. Consumes ai.parse output; emits per-page labels and a byLabel map (label -> page indices) that supports NON-contiguous selections. Feed byLabel.<label> straight into ai.vision pageIndices to inspect scattered pages of a type (e.g. every signature or property-photo page). |
| Inspect Pages (Vision) | ai.vision | Inspect rendered page images with a vision model and return structured JSON matching a schema. The visual counterpart to Extract Data: use it for conclusions that live in the pixels rather than the text (is the document signed? are the photos usable?). Renders PDF, image, or Office/Word inputs; route to specific pages with an ai.split page range to keep it cheap. |
| Search Files | ai.search-files | Investigate a ZIP archive with a question and return an answer plus file citations. Read-only: the step opens files in the archive and never writes back. ZIP is the only accepted format in this version. Optionally scope the search to a folder prefix and cap how many files and investigation turns may run. |
Transform steps
| Step | Type | Summary |
|---|---|---|
| Set Value | transform.set | Set key-value pairs in the output object |
| Remove Fields | transform.remove | Remove specified fields from an object |
| Combine Data | transform.combine | Merge multiple objects or concatenate arrays |
| Split Data | transform.split | Split a string by delimiter or extract keys from an object |
| Merge Inputs | transform.merge | Merge multiple named inputs into a single output |
| Fill Template | transform.template | Fill a DOCX or XLSX workspace template with data from previous steps. Reference a tmpl_… id, or a local ./templates/file.xlsx path (CLI push uploads it). Git agent templates use the fill-template skill instead and cannot be referenced here. File IDs (file_…) are not accepted. Placeholders are auto-detected. In the Office file use {placeholder} and {table:array.prop}; {{placeholder}} in an XLSX file is rejected ({{ }} is YAML Liquid only). |
| Embed PDF Text | transform.pdf-embed | Embed OCR text layer into scanned PDFs/images to make them searchable |
| Spreadsheet to JSON | transform.xlsx-to-json | Convert an XLS or XLSX spreadsheet to a JSON array of row objects. Supports headerless files, named or positional columns, displayed text, and a single rectangular range. |
| JSON to XLSX | transform.json-to-xlsx | Convert JSON rows into an XLSX spreadsheet. Pair with transform.xlsx-to-json. Formula-looking strings stay text; nested cell values are rejected. |
| Script | transform.script | Execute a TypeScript function in a QuickJS sandbox. Input keys become function parameters in any order, and the required : R return-type annotation IS this step’s output schema: inputs: { items, taxRate } accepts function script(taxRate: …, items: …): R { … }. |
| Text Chunker | transform.text-chunker | Split long text into chunks with regex-anchored boundaries, overlap, and header preservation. Accepts raw text or a parsed-document object; chunks carry source page indexes when pages are provided. |
| Regex Extract | transform.regex-extract | Pull named fields from text via regex patterns (deterministic counterpart to ai.extract). Accepts raw text or a parsed-document object; matches carry _evidence.pageIndex when pages are provided. |
| List Archive | transform.archive-list | List files inside a ZIP archive. Returns sorted normalized paths with compressed and uncompressed sizes. Optionally filter by folder prefix or substring, then page with offset and limit. ZIP is the only accepted format in this version. Pair with foreach or parallel_map and transform.archive-extract to open individual files. |
| Extract Archive File | transform.archive-extract | Extract exactly one file from a ZIP archive and store it as a run output file. Downstream steps can pass {{ steps.extract.output }} into Parse, Vision, or another archive step. Nested ZIPs are stored as ZIP files, not unpacked. Each extraction is capped at 64 MiB. ZIP is the only accepted format in this version. |
Action steps
| Step | Type | Summary |
|---|---|---|
| HTTP Request | action.http | Make an HTTP request to an external API |
| Invoke Workflow | action.invoke-workflow | Execute another workflow and return its output |
| Website Reader | action.website-reader | Fetch a webpage and convert content to markdown |
| Send Email | action.email | Send an email with optional attachments via a selected email server. At most 10 recipients combined across to, cc, and bcc. |
Control steps
| Step | Type | Summary |
|---|---|---|
| Condition | control.if | Branch execution based on a condition expression |
| Switch | control.switch | Multi-way routing: resolve an expression and run the first case whose value matches (else default). Cleaner than a nested control.if chain for routing an item to one of N pipelines by a discriminator field like a document type. |
| For Each | control.foreach | Loop over an array and execute steps for each item |
| Parallel Map | control.parallel_map | Iterate over an array with concurrent execution up to a limit |
| Parallel | control.parallel | Execute multiple branches concurrently |
| Wait | control.wait | Pause workflow execution for a specified duration |
| Human Review | control.human_review | Pause the run for selective field confirmation or correction, then continue with the reviewed data. |
| Fail | control.fail | Terminate the workflow with a typed status code + message. With an optional condition, only fails when the condition is truthy; otherwise always fails when reached. Pair with ai.classify or any prior step to fail fast on bad inputs. |