ReadFile¶
ReadFile is the native path → bytes step: it reads a file the route names
at call time into the exchange body. It is the input half of a document skill —
the caller supplies a path (e.g. as a tool-call argument), read-file loads the
bytes, and a downstream component consumes them (pdf://?op=extractText,
xlsx://, docling://, vlm://, …).
It complements the two file:// read paths without needing an endpoint or a
directory to configure:
| Path | Role | Reads |
|---|---|---|
file:// polling consumer (trigger:) |
route source | files it discovers in a fixed directory |
file://?op=read (producer step) |
mid-route | a file relative to a configured, jailed directory |
read-file (this step) |
mid-route | a single caller-named path — no endpoint, no directory |
YAML form¶
steps:
- read-file:
path: { starlang: payload.path } # or a bare string: path: /forms/y.pdf
as: bytes # bytes (default) | text
fail-if-missing: true # default true
max-size: 25MB # optional guard; "" = unlimited
| Field | Type | Default | Description |
|---|---|---|---|
path |
value | required | The file to read. A bare string is a constant path; { starlang: <expr> } evaluates per-exchange (e.g. payload.path from a tool-call arg); { constant: <path> } is the explicit constant form. |
as |
enum | bytes |
Body type. bytes yields []byte (binary-safe — no charset mangling); text yields a string. |
fail-if-missing |
bool | true |
A missing file is a hard, catchable error (surfaced to do-try / on-exception). When false, a missing file leaves an empty body and sets HelixFileMissing=true. |
max-size |
string | unlimited | Reject files larger than this human byte size (10MB, 512KB, 1048576) before reading them into memory. Units are binary (KB = 1024). |
Constructor: NewReadFile(path engine.Expression, asText, failIfMissing bool, maxSize int64) *ReadFile.
Behaviour¶
- Evaluates
pathagainst the exchange (constant or Starlang). An empty or nil result is an error. os.Statthe path. A missing file followsfail-if-missing; a directory is an error; a file overmax-sizeis an error.- Reads the bytes and sets the body (
[]byte, orstringwhenas: text). - Stamps the same provenance headers a polled file /
file://?op=readgets, so downstream steps behave identically regardless of how the bytes arrived:HelixFileName,HelixFilePath,HelixFileLength(int64),HelixFileLastModified(time.Time), andContent-Type(probed from the extension).
The path is used verbatim (an absolute path reads that file; a relative path
resolves against the process working directory). Unlike file://?op=read, there
is no endpoint directory and therefore no jail — read-file is the endpoint-free
step for trusted, caller-named paths (e.g. a skill tool an agent invokes). Point
untrusted input through file://?op=read with a sandbox directory instead.
Examples¶
A document-input tool: the agent supplies a path at call time, the step turns it
into bytes, and pdf:// extracts the text.
tools:
- id: pdf_extract_text
description: extract text from a PDF the caller names
input: { path: { type: string, required: true } }
output: { text: { type: string } }
steps:
- read-file: { path: { starlang: payload.path } }
- target: "pdf://x?op=extractText"
- transform: { starlang: 'write({ text: payload }, "application/json")' }
Load a JSON config by constant path — a JSON body is auto-parsed, so its fields are addressable directly in the next step:
steps:
- read-file: { path: /etc/app/settings.json }
- transform: { starlang: '{ mode: payload.env, retries: payload.retries }' }
Tolerate a missing file and branch instead of failing:
steps:
- read-file: { path: { starlang: payload.path }, fail-if-missing: false }
- choice:
when:
- starlang: 'headers["HelixFileMissing"] == "true"'
steps:
- log: { message: "no file at ${payload.path}, using default" }
Source¶
pkg/processor/read_file.go
See also¶
file://—op=read(jailed, endpoint-relative) and the polling consumer.- poll_enrich — enrich the current exchange from a polled endpoint.
- pdf, xlsx, docling — document components that consume the bytes.