Skip to content

Artifacts

Every session has a full filesystem. After the agent finishes, pull individual files or walk the entire tree and download the workspace to your machine.

Read a Single File

typescript
// Text
const src = await session.getFile("/workspace/src/index.ts");
console.log(src);

// Binary
const buf = await session.getFileBuffer("/workspace/output/chart.png");

Walk the File Tree

List all files the agent created, then download them:

typescript
import { writeFileSync, mkdirSync } from "fs";
import { dirname, join } from "path";

// List all files (excluding node_modules)
const tree = await session.shell(
    "find /workspace -type f -not -path '*/node_modules/*' -not -name 'package-lock.json' | sort"
);
const files = tree.stdout.trim().split("\n").filter(Boolean);

console.log("Files:");
for (const f of files) {
    console.log(`  ${f.replace("/workspace/", "")}`);
}

Download the Full Workspace

typescript
const outDir = "output/project";

for (const remotePath of files) {
    const relative = remotePath.replace("/workspace/", "");
    const localPath = join(outDir, relative);
    mkdirSync(dirname(localPath), { recursive: true });

    try {
        const content = await session.getFile(remotePath);
        writeFileSync(localPath, content);
        console.log(`${relative} (${content.length} chars)`);
    } catch {
        try {
            const buf = await session.getFileBuffer(remotePath);
            writeFileSync(localPath, Buffer.from(buf));
            console.log(`${relative} (${buf.byteLength} bytes, binary)`);
        } catch {
            console.log(`${relative} (skipped)`);
        }
    }
}

TIP

getFile() returns a string and works for text files. getFileBuffer() returns an ArrayBuffer and works for everything — use it as a fallback for binary files.

Verify with Tests

After downloading, or even before — run the agent's tests directly in the sandbox:

typescript
const test = await session.shell("cd /workspace && npx tsx --test tests/*.test.ts 2>&1");
console.log(test.stdout);
console.log(`Exit code: ${test.exitCode}`);

Check Usage

typescript
const metrics = await session.getMetrics();
console.log(`${metrics.steps} steps`);
console.log(`${metrics.toolCalls} tool calls`);
console.log(`$${metrics.cost.toFixed(4)}`);

Full Example

Seed a spec file, have the agent build a project, then download everything locally:

typescript
import { createClient } from "swarmlord";
import { writeFileSync, mkdirSync } from "fs";
import { dirname, join } from "path";

const client = createClient({
    apiKey: process.env.SWARMLORD_API_KEY!,
});

const agent = client.agent({
    name: "build",
    config: { permission: "allow" },
});
const session = await agent.createSession();

// Seed the sandbox
const spec = `# json2csv CLI
Convert JSON arrays to CSV.

## Files to create
- src/converter.ts — flattenObject() + convertToCSV()
- src/index.ts — read stdin, write CSV to stdout
- tests/converter.test.ts — Node built-in test runner`;

const specBase64 = Buffer.from(spec).toString("base64");
await session.shell("mkdir -p /workspace/cli && cd /workspace/cli && npm init -y && npm install tsx");

// Build
await session.send(
    {
        parts: [
            {
                type: "text",
                text: "Read the attached spec and implement everything in /workspace/cli/. Run the tests.",
            },
            {
                type: "file",
                url: `data:text/markdown;base64,${specBase64}`,
                mime: "text/markdown",
                filename: "SPEC.md",
            },
        ],
    },
    { onText: delta => process.stdout.write(delta) }
);

// Download
const tree = await session.shell(
    "find /workspace/cli -type f -not -path '*/node_modules/*' -not -name 'package-lock.json' | sort"
);
const files = tree.stdout.trim().split("\n").filter(Boolean);

for (const remotePath of files) {
    const relative = remotePath.replace("/workspace/cli/", "");
    const localPath = join("output/cli", relative);
    mkdirSync(dirname(localPath), { recursive: true });

    try {
        const content = await session.getFile(remotePath);
        writeFileSync(localPath, content);
        console.log(`${relative} (${content.length} chars)`);
    } catch {
        try {
            const buf = await session.getFileBuffer(remotePath);
            writeFileSync(localPath, Buffer.from(buf));
            console.log(`${relative} (${buf.byteLength} bytes, binary)`);
        } catch {
            console.log(`${relative} (skipped)`);
        }
    }
}

// Verify
const test = await session.shell("cd /workspace/cli && npx tsx --test tests/*.test.ts 2>&1");
console.log(test.stdout);

const metrics = await session.getMetrics();
console.log(`${metrics.steps} steps · ${metrics.toolCalls} tools · $${metrics.cost.toFixed(4)}`);

await session.end();

SDK released under the MIT License.