Skip to content

Best Practices

Shell-First for Deterministic Work

Use session.shell() for anything with a known command — file setup, dependency installation, script execution, data processing. Reserve session.send() for work that needs the LLM's judgment.

typescript
const session = await agent.createSession({ title: "data pipeline" });

// Deterministic: install deps, run scripts, prepare files
await session.shell("pip install pandas");
await session.shell("python3 /workspace/transform.py");
const result = await session.shell("wc -l /workspace/output.csv");

// Read results directly — no LLM needed
const csv = await session.getFile("/workspace/output.csv");

// Only NOW involve the LLM — for interpretation
await session.send("Analyze the patterns in /workspace/output.csv and write insights to /workspace/report.md");

putFile / putFileBuffer for Uploading

Write files directly to the workspace without an LLM round-trip:

typescript
import { readFileSync } from "fs";

const session = await agent.createSession();

// Upload a PDF — no LLM needed
await session.putFileBuffer("/workspace/input.pdf", readFileSync("datasheet.pdf"));

// Upload a config as text
await session.putFile("/workspace/config.json", JSON.stringify({ mode: "strict" }));

getFile + Client-Side Processing

Read files from the workspace and process them in TypeScript:

typescript
// Run a Python script that produces JSON
await session.shell("python3 /workspace/extract.py > /workspace/manifest.json");

// Read and parse client-side — zero LLM tokens
const manifest = JSON.parse(await session.getFile("/workspace/manifest.json"));

// Use the parsed data to build LLM prompts
for (const item of manifest.items) {
    await session.send(`Analyze item: ${item.name}\n\nData: ${item.raw}`);
}

Structured Metadata for Aggregation

When multiple agents produce artifacts that need to be combined, have each agent write structured metadata (YAML frontmatter, JSON sidecar) alongside its output. Aggregate deterministically client-side.

Anti-pattern: Ask one LLM to read N files and summarize them all. At scale (50+ files), it grabs first lines or hallucinates.

Pattern: Each agent writes frontmatter during processing — when it has full context:

markdown
---
title: "Electrical Characteristics"
section: "5.1 Absolute Maximum Ratings"
summary: "Voltage limits, current ratings, and temperature ranges for all power domains"
has_figures: false
---

# Page 52

...

Then aggregate client-side:

typescript
// Parse frontmatter from each file — instant, zero tokens
const metas = pages.map(content => parseFrontmatter(content));

// Build index deterministically
const index = metas.map(m => `| [${m.page}](page_${m.page}.md) | ${m.title} | ${m.summary} |`);

Parallel Sessions

SDK sessions created via createSession() are independent cloud resources. There is no concurrency limit beyond your account's rate limits — launch as many as you need.

typescript
// All batches run in parallel — don't artificially throttle
const results = await Promise.all(
    batches.map(async batch => {
        const session = await agent.createSession({ title: `batch ${batch.id}` });
        const result = await session.send(batch.prompt);
        return { batch, session, result };
    })
);

SDK sessions vs task tool

The task tool (used inside agent conversations) limits to 3 concurrent sub-agents within one session. SDK createSession() calls are independent — no shared concurrency limit.

Output Verification

SendResult.error only catches infrastructure failures (model errors, timeouts). If the agent can't do what you asked and says "I need more info," error is null and the turn appears successful.

Use expectedOutputs to verify the agent produced what you need:

typescript
const result = await session.send("Process the data and write results to /workspace/output.csv", {
    expectedOutputs: ["/workspace/output.csv"],
});

if (result.outputErrors?.length) {
    console.error("Missing outputs:", result.outputErrors);
    // Retry, fall back, or fail explicitly
}

Or verify manually with verifyOutputs:

typescript
const missing = await session.verifyOutputs(["/workspace/report.md", "/workspace/data.json"]);
if (missing.length > 0) {
    // Handle missing files
}

Session Forking

forkSession copies conversation history and server-tracked files. Files created solely via session.shell() are not carried over — they exist only in the original session's container.

To share shell-created files with forked sessions, either:

  1. Read them via getFile() and pass content inline in the prompt
  2. Use putFile() to write them into the forked session
  3. Use a Pipeline with seedSession (files flow automatically between phases)
typescript
// Shell-created files won't be in the fork
await baseSession.shell("python3 /workspace/process.py"); // creates output.json

// Option 1: Read and pass inline
const data = await baseSession.getFile("/workspace/output.json");
const fork = await agent.forkSession(baseSession.id);
await fork.send(`Here is the data:\n${data}\n\nAnalyze it.`);

// Option 2: putFile into the fork
const fork2 = await agent.forkSession(baseSession.id);
await fork2.putFile("/workspace/output.json", data);
await fork2.send("Analyze /workspace/output.json");

Pipeline with Pre-Computed Data

Use seedSession to start a pipeline from an existing session's workspace:

typescript
// Phase 0: deterministic setup via shell
const setup = await agent.createSession({ title: "setup" });
await setup.putFileBuffer("/workspace/input.pdf", readFileSync("doc.pdf"));
await setup.shell("python3 /workspace/split.py");

// Pipeline picks up from setup session's workspace
const result = await pipeline.run(agent, {
    vars: {},
    seedSession: setup.id,
    on: { phaseStart: p => console.log(p.name) },
});

Sandbox Dependencies

The sandbox includes Python 3.10, Node.js 22, git, curl, and common libraries. For additional Python packages:

typescript
// --user fallback handles the current sandbox permission model
await session.shell("pip install -q mypackage || pip install -q --user mypackage");

// When --user install is used, ensure the module is on the path
await session.shell("PYTHONPATH=$(python3 -m site --user-site 2>/dev/null):$PYTHONPATH python3 script.py");

Pre-installed Python packages: numpy, pandas, matplotlib, pydantic, requests. Pre-installed Node packages: zod, sharp.