Concepts
Capturing Values
Use readFile(path, as) to pull file contents out of the sandbox and into WorkflowResult.vars.
SandboxBuilder doesn't return ExecHandle — ops are queued, not executed. To get a value out of the sandbox, write it to a file inside the container and read it back with readFile.
readFile
sb.exec("node --version > /tmp/ver.txt");
sb.readFile("/tmp/ver.txt", "nodeVersion");After the workflow resolves, vars.nodeVersion contains the file's content as a string.
const { vars } = await workflow(client)
.sandbox(opts, (sb) => {
sb.exec("node --version > /tmp/ver.txt");
sb.readFile("/tmp/ver.txt", "nodeVersion");
})
.result();
console.log(vars.nodeVersion); // "v22.x.x\n"Multiple values
Capture as many values as you need — each gets its own key:
const { vars } = await workflow(client)
.sandbox(opts, (sb) => {
sb.exec("node --version > /tmp/node.txt");
sb.exec("npm --version > /tmp/npm.txt");
sb.exec("uname -r > /tmp/kernel.txt");
sb.readFile("/tmp/node.txt", "node");
sb.readFile("/tmp/npm.txt", "npm");
sb.readFile("/tmp/kernel.txt", "kernel");
})
.result();
console.log(vars); // { node: "v22.x.x\n", npm: "10.x.x\n", kernel: "..." }Passing values between sequence steps
readFile values are available in the next step via prev.vars:
await workflow(client)
.sequence([
{
image: "node:22",
resources: opts.resources,
run: (sb) => {
sb.exec("npm run build:version > /tmp/version.txt");
sb.readFile("/tmp/version.txt", "version");
},
},
{
image: "ubuntu:22.04",
resources: opts.resources,
run: (sb, prev) => {
const version = String(prev.vars.version).trim();
sb.exec(`./deploy.sh --version ${version}`);
},
},
])
.pipe(process.stdout);stdout
The combined stdout from all exec calls is also available in WorkflowResult.stdout. For selective capture, readFile is more reliable than parsing stdout.
const { stdout } = await workflow(client)
.sandbox(opts, (sb) => {
sb.exec("npm test");
})
.result();