Artifacts
Upload, download, and share persistent files across sandboxes.
Artifacts
Artifacts provide persistent file storage that lives outside any single sandbox. Use them to export outputs, share files between sandboxes, and build data pipelines.
Artifact operations are available on the extended client (StateSetSandboxExtended in Node.js).
Upload an Artifact
Upload a file from a running sandbox to persistent storage.
Node.js
typescript
import { StateSetSandboxExtended } from '@stateset/sandbox-sdk';
const client = new StateSetSandboxExtended({
baseUrl: 'https://api.sandbox.stateset.app',
authToken: process.env.SANDBOX_API_KEY!,
});
const artifact = await client.uploadArtifact(sandboxId, {
path: '/workspace/output/report.pdf',
remote_path: 'reports/weekly-report.pdf',
content_type: 'application/pdf',
metadata: { generated_by: 'analytics-pipeline' },
});
console.log(`Artifact ID: ${artifact.id}`);
console.log(`Size: ${artifact.size} bytes`);
console.log(`Checksum: ${artifact.checksum}`);Python
python
artifact = client.upload_artifact(
sandbox_id,
path="/workspace/output/report.pdf",
remote_path="reports/weekly-report.pdf",
content_type="application/pdf",
metadata={"generated_by": "analytics-pipeline"},
)
print(f"Artifact ID: {artifact.id}")
print(f"Size: {artifact.size} bytes")Download an Artifact
Download a previously stored artifact into a sandbox.
Node.js
typescript
await client.downloadArtifact(sandboxId, artifact.id, '/workspace/input/report.pdf');
// Verify the file
const result = await client.execute(sandboxId, {
command: ['ls', '-la', '/workspace/input/report.pdf'],
});
console.log(result.stdout);Python
python
client.download_artifact(sandbox_id, artifact.id, "/workspace/input/report.pdf")
result = client.execute(sandbox_id, command=["ls", "-la", "/workspace/input/report.pdf"])
print(result.stdout)Get a Presigned Download URL
Generate a time-limited URL to download an artifact directly (useful for browser downloads or sharing).
Node.js
typescript
const { url, expires_in } = await client.getArtifactUrl(artifact.id, 3600);
console.log(`Download URL (valid for ${expires_in}s): ${url}`);Python
python
result = client.get_artifact_url(artifact.id, expires_in=3600)
print(f"Download URL (valid for {result.expires_in}s): {result.url}")List Artifacts
Node.js
typescript
// List all artifacts for the organization
const { artifacts } = await client.listArtifacts();
// Filter by sandbox
const { artifacts: sandboxArtifacts } = await client.listArtifacts(sandboxId);
for (const a of artifacts) {
console.log(`${a.id} — ${a.path} (${a.size} bytes, ${a.createdAt})`);
}Python
python
# All artifacts
artifacts = client.list_artifacts()
# Filter by sandbox
artifacts = client.list_artifacts(sandbox_id=sandbox_id)
for a in artifacts:
print(f"{a.id} — {a.path} ({a.size} bytes)")Use Cases
Export Build Outputs
typescript
// Run build inside sandbox
await client.execute(sandboxId, { command: ['npm', 'run', 'build'] });
// Upload the build artifact
const artifact = await client.uploadArtifact(sandboxId, {
path: '/workspace/dist/bundle.js',
remote_path: `builds/${buildId}/bundle.js`,
content_type: 'application/javascript',
});Share Data Between Sandboxes
typescript
// Sandbox A: produce data
const artifact = await client.uploadArtifact(sandboxA, {
path: '/workspace/data/processed.csv',
});
// Sandbox B: consume data
await client.downloadArtifact(sandboxB, artifact.id, '/workspace/input/processed.csv');Data Pipeline
python
# Step 1: Extract
extract_result = client.execute(sandbox_id, command=["python3", "extract.py"])
# Step 2: Upload intermediate result
artifact = client.upload_artifact(sandbox_id, path="/workspace/raw_data.parquet")
# Step 3: Download into a fresh sandbox for transformation
transform_sandbox = client.create(cpus="4", memory="8Gi", timeout_seconds=600)
client.download_artifact(transform_sandbox.sandbox_id, artifact.id, "/workspace/raw_data.parquet")
client.execute(transform_sandbox.sandbox_id, command=["python3", "transform.py"])
# Step 4: Upload final output
final = client.upload_artifact(transform_sandbox.sandbox_id, path="/workspace/output.parquet")
print(f"Pipeline complete. Final artifact: {final.id}")Agent Session Artifacts
If you are using agent sessions, the extended client provides a convenience method:
typescript
import { StateSetSandboxExtended } from '@stateset/sandbox-sdk';
const client = new StateSetSandboxExtended({
baseUrl: 'https://api.sandbox.stateset.app',
authToken: process.env.SANDBOX_API_KEY!,
});
// Upload from the session's current sandbox (auto-tags with session ID)
const artifact = await client.uploadAgentSessionArtifact(sessionId, {
path: '/workspace/result.json',
metadata: { step: 'final' },
});