Skip to content

feat: add read: file source — process local files as rows (D.1) - #72

Merged
mirpo merged 2 commits into
mainfrom
feat/read-file-source
Jul 18, 2026
Merged

feat: add read: file source — process local files as rows (D.1)#72
mirpo merged 2 commits into
mainfrom
feat/read-file-source

Conversation

@mirpo

@mirpo mirpo commented Jul 18, 2026

Copy link
Copy Markdown
Owner

read: — run a workflow over your own local files

The headline of Block D (file-in): a native read: step that turns local files into rows, so you can process your own data with no shell/download costume.

- name: tickets
  read: ./docs/*.md          # one row per file: {path, name, content}
- name: triage
  forEach: tickets
  prompt: "Triage: {{.item.content}}"

Formats (by extension, overridable with format:)

Input Rows
glob / directory / .txt / .md one row per file: {path, name, content}
.csv / .tsv one row per record; columns → fields
.jsonl one row per line (parsed JSON)

Design

  • read: is a new inferred step type (like prompt/run/jq).
  • Read path resolves relative to CWD (your files); rows materialize to outputFolder like a transform, so from:/forEach: consume them unchanged.
  • Glob results always sorted (deterministic); empty match is an error.

Unlocked (the n8n-lite bridge)

Triage a folder of documents, enrich a CSV, extract from your .md/.txt, re-process an existing .jsonl — batch LLM over your own data.

Tests (TDD)

  • fs helpers (glob+sort+dir, CSV, text) — pure, golden
  • ReadStep.Run — files / csv / jsonl / empty-glob
  • step-type inference + preprocess validation (format inference, rejects read+count/imagePath)
  • runner e2e: read a folder → forEach → one row per file
  • New example process-my-files (read tickets → triage), live-verified on qwen3:1.7b (3 files → correct billing/bug/feature classification, 0 retries)

Full suite + golangci-lint clean. Additive — shell + DuckDB stays the tool for parquet/complex sources.

Follow-ups (next PR): Phase 2 — unify the image glob into read: + an image: attach field on prompt steps (removes imagePath); and review/simplify the complex getSourceDataFromLine source-reading path.

mirpo added 2 commits July 18, 2026 15:02
A native `read:` step turns local files into rows, so you can run a workflow
over your own data without a shell costume:

- glob / directory / a single .txt|.md  -> one row per file: {path, name, content}
- .csv / .tsv                            -> one row per record, columns as fields
- .jsonl                                 -> one row per line (parsed JSON)

`read:` is a new inferred step type (like prompt/run/jq). Format is inferred
from the extension and overridable with `format:`. The read path resolves
relative to CWD (your files); rows materialize to outputFolder like a transform,
so `from:`/`forEach:` consume them unchanged. Glob results are always sorted for
determinism; an empty match is an error.

New example process-my-files (read a folder of support tickets -> triage each),
live-verified on qwen3:1.7b. TDD throughout: fs helpers, ReadStep.Run,
step-type inference, preprocess validation, and a runner e2e.

Additive — shell + duckdb stays the tool for parquet/complex sources.
Follow-ups: unify the image glob into read: + an `image:` attach field (kills
imagePath); review/simplify the complex getSourceDataFromLine source-reading.
- Resolve the format dispatch once before the loop instead of re-switching per
  file; the loop body is now just loadFile(path).
- Reuse transform's limitedEmit for write+count instead of hand-rolling
  WriteJSON + written++ in each format branch; emitJSONLines emits via the same
  callback.
- fs.GlobFiles: plain `var files []string` instead of the `candidates[:0]`
  in-place reuse trick.
- Update the getSourceDataFromLine doc comment to mention read steps.
@mirpo
mirpo merged commit 8e368a1 into main Jul 18, 2026
3 checks passed
@mirpo
mirpo deleted the feat/read-file-source branch July 18, 2026 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant