Environments
Transfer between VFS and an environment
Use vfs_materialize to copy a VFS file or directory onto the active machine,
and vfs_capture to save machine output into a VFS workspace. This is the
bridge between an agent’s persistent files and the filesystem its commands
use. The copies remain independent after the transfer.
For example, copy a review skill to the machine before running it, then retain the resulting output in the workspace:
vfs_materialize( source_vfs_path = "/workspace/skills/review", destination_environment_path = "./skills/review")
vfs_capture( source_environment_path = "./output", destination_vfs_path = "/workspace/results")Each destination is exact: the source’s basename is not appended. In this
example, the contents of ./output become /workspace/results, not
/workspace/results/output. Binary files, empty directories, and executable
flags are preserved on supported Linux and macOS filesystems.
Prepare the attachments
The session needs an attached workspace or snapshot and an active environment. The two operations require different access:
| Operation | VFS access | Active environment access |
|---|---|---|
| Materialize | Read or edit | Edit files or higher |
| Capture | Edit on a workspace | Read files or higher |
Snapshot attachments are read-only, so they can supply a materialize source but cannot receive captured output. Select a path inside one attachment; a synthetic VFS directory spanning several attachments cannot be transferred as one tree. Neither operation requires permission to run commands.
The transfer tools appear when the session’s attachments permit them. A call still checks the active environment’s access, readiness, and transfer support. See Using environments for how attachments and selection work.
Replace a destination and retain the result
The default on_existing policy is replace. Replacing a directory removes
entries found only in that destination and publishes the complete replacement
at once. Sibling paths are untouched. Use on_existing = "error" when an
existing destination should cause the operation to fail instead.
Missing destination parents are created where permitted. Non-directory ancestors and environment symlinks are rejected. A failed materialize can leave newly created parent directories, but it does not publish a partial replacement. There is no automatic merge or ongoing synchronization.
Capture first saves an immutable VFS snapshot with the selected content at
/selection, then attempts to update the workspace. If another writer changed
that workspace during transfer, the result reports published: false and
retains the snapshot reference. Inspect that result before treating a capture
as published; the saved snapshot lets you recover the output without
overwriting the other writer’s changes.
Content reuse and large files
Transfers compare file-content digests and send only missing bytes. A repeated copy or rename can therefore reuse content already present at the destination or in Lightspeed storage. Files still need local verification and sometimes copying, so reused bytes do not mean the operation has no disk cost.
Large files move in bounded chunks rather than one large tool argument or response. The daemon’s default limits are 100,000 entries, depth 64, one TiB per file and selected tree, and 24 hours per operation. There are also inventory size and concurrency limits. Allow enough machine disk for the existing tree, missing uploads, and the staged replacement. Overlapping materialization destinations are rejected.
The tool result reports references and counts rather than file payloads. Exact limits and wire sizes are defined in the inventory types; the transfer implementation describes content reuse and workspace publication.
Environment data-plane API
Clients implementing their own transfers use EnvironmentDataClient::transfer
and the fs/transfer protocol after negotiating filesystemTransfer. The
daemon interface handles machine files; the Lightspeed tools above connect it
to VFS and content-addressed storage.
| Actions | Purpose |
|---|---|
begin, advance |
Start an operation and advance scanning or staging. |
inventory, append, missing |
Exchange inventory pages and identify missing content. |
read, write |
Transfer bounded file chunks at explicit offsets. |
commit |
Verify the capture or publish the staged replacement. |
status, abort |
Inspect progress or abandon incomplete work. |
Keep the same operation ID and input when retrying. Completed-operation receipts survive daemon restart until expiry, so a repeated commit does not overwrite subsequent local edits. A partially staged operation does not resume transparently after a daemon crash: inspect the destination and abort it before starting a new operation.
The transfer protocol
defines pagination, retry, and chunk semantics. The older fs/materialize and
fs/capture methods remain compatibility adapters for small copies, with
8 MiB, 1,024-entry, and 30-second limits.
Generic filesystem scans
For discovery rather than copying, EnvironmentDataClient::scan sends
fs/scan after negotiating filesystemScan. A client selects roots and
patterns and can request metadata, inline content, or SHA-256 digests. This is
the lower-level operation used to discover files such as prompts and skills.
Complete scans can return a fingerprint for conditional ifNoneMatch requests.
Incomplete scans return diagnostics and never claim the result is unchanged.
A metadata-only fingerprint covers metadata, not file bytes. Scans have small
response and time limits; use transfer sessions for large inventories and
content. The scan types
defines those request fields and responses.
Filesystem boundary and consistency
Transfers reject symlinks, special files, and non-UTF-8 names. Replacement uses atomic filesystem operations on Linux and macOS; unsupported filesystems fail instead of exposing a partly replaced tree. Windows execution support is not implemented. Platform-specific details live beside the daemon transfer code.
Capture observes a live filesystem. It verifies metadata and content while reading and fails on detected changes, but it is not an operating-system snapshot. Pause writers when a result needs consistency across several files. The daemon’s process permissions still determine what it can access; transfer checks do not isolate commands running as the same OS user from its state.