| name | codemation-workspace-files |
| description | ListWorkspaceFiles + ReadWorkspaceFile nodes — read files from the shared workspace pool. Covers read-by-filename (latest-wins), pinned fileId, binary slot handoff, and the raw-upload → concierge-digests → workflow-reads-derived-file pattern. Read before building any workflow that reads workspace files. |
| compatibility | Codemation core-nodes-workspace-files. Requires WORKSPACE_ID and BLOB_STORAGE_* env vars. |
| tags | workspace, files, binary, storage, read, csv, json |
| uses | @codemation/core-nodes-workspace-files |
Codemation Workspace Files
Mental model
Workflows read the shared workspace file pool; they do not write to it. Files are
created and managed on the control-plane side (the Files UI, the concierge, the
DocumentScanner). The framework's role is to provide ListWorkspaceFiles and
ReadWorkspaceFile as pure read nodes.
The headline scenario is: a user uploads a raw PDF; the concierge digests it into a
structured JSON; the workflow reads the derived JSON, not the raw bytes. Workflows
never touch raw uploads directly.
When to use / when NOT
Use ReadWorkspaceFile when a workflow needs data that lives in the workspace pool
(pricing sheets, config JSON, concierge-derived documents, CSV exports).
Use ListWorkspaceFiles to discover what files exist or to drive a fan-out (one item per file).
Do NOT use these nodes to write files — writing is CP-mediated and deferred to v2.
Do NOT base64-encode bytes onto item.json. Binary payloads always flow through
item.binary via ctx.binary.
Quickstart
import { readWorkspaceFileNode } from "@codemation/core-nodes-workspace-files";
readWorkspaceFileNode.create({ filename: "pricing.csv", binarySlot: "data" }, "Read pricing CSV", "read-pricing-csv");
readWorkspaceFileNode.create(
{ fileId: "abc123def456", binarySlot: "data" },
"Read pinned pricing CSV",
"read-pricing-pinned",
);
For full patterns (parse the bytes, scenario walkthrough, list + filter), use your
harness's example-discovery tool: find_examples({ query: "workspace files" }).
Resolution modes
| Mode | Config | Behaviour |
|---|
| latest-wins (default) | filename: "pricing.csv" | Reads the newest file with that name. Next upload of the same name is what the next run reads. |
| pinned fileId | fileId: "abc123..." | Reads that exact, immutable version forever. A new upload never changes this ref. |
Use latest-wins for "always use the current sheet" patterns.
Use pinned fileId for reproducible/auditable runs (e.g., regression tests, compliance audits).
Binary slot handoff
ReadWorkspaceFile streams the file's bytes into item.binary[binarySlot] (default "data").
The node emits:
{
fileId: string;
filename: string;
contentType: string;
size: number;
lastModified: string;
binarySlot: string;
}
Downstream nodes read the bytes via ctx.binary.openReadStream(item.binary["data"]).
The bytes are never base64-encoded on item.json.
Concierge → digest → workflow pattern
This is the intended headline flow:
User uploads PDF → CP Files UI stores it in the workspace pool
Concierge sees upload → DocumentScanner digests it → writes "report-digested.json" back
Workflow runs (schedule/webhook) → ReadWorkspaceFile("report-digested.json") → acts
The workflow is decoupled from the upload event. It reads the derived file that the
concierge produced, not the raw upload. The concierge's job is to bridge the raw-upload world
and the structured-data world.
Key boundaries:
- CP side (write): raw file ingest, concierge digest, derived file write, Files UI.
- Workflow side (read):
ReadWorkspaceFile + ListWorkspaceFiles only.
Anti-patterns
- Do NOT tell users to read the raw PDF upload in a workflow — point at the concierge-derived JSON.
- Do NOT base64-encode file bytes onto
item.json — use item.binary[slot] + ctx.binary.
- Do NOT attempt to write a file from a workflow node — there is no write surface in v1.
- Do NOT assume
WORKSPACE_ID is always set — in local dev without CP integration, the storage
token resolves to undefined. Add a guard if your workflow runs in dev mode.
Node reference
listWorkspaceFilesNode
listWorkspaceFilesNode.create(
{
filenameFilter?: string;
},
"List files",
"list-files",
)
Output per item: { fileId, filename, contentType, size, lastModified }. Sorted newest-first.
readWorkspaceFileNode
readWorkspaceFileNode.create(
{
filename?: string;
fileId?: string;
binarySlot?: string;
maxBytes?: number;
},
"Read file",
"read-file",
)
Either filename or fileId must be set. Output: metadata JSON + bytes in item.binary[binarySlot].