Compute Workspace
Storage
Per-tenant object storage, outputs produced by skills and dedicated tasks land here, auto-filed into a folder named after the producing skill.
How it works
Every workspace has its own object store. When a skill or dedicated task writes an output, an object row is registered, a storage_key in the tenant bucket plus category, source, size_bytes and an optional task_id. Runs auto-file into a folder named after the producing skill; you can create your own folders to organize further. Every route is scoped by business_profile_id, the workspace the hyb_* key belongs to.
Browse folders and objects
/api/v1/tenant-objects/folders/api/v1/tenant-objectsList folders (each with an object count and total bytes), or list objects directly. Pass task_id to narrow objects to a single dedicated-task run, or folder_id to one folder.
| Parameter | Type | Description |
|---|---|---|
business_profile_idrequired | string (uuid) | The workspace to list. |
task_id | string | Filter objects to one dedicated-task run. |
folder_id | string (uuid) | Filter objects to one folder. |
stimulir storage folders
stimulir storage list
stimulir storage list --task-id <task-id>from stimulir import StimulirClient
client = StimulirClient() # reads STIMULIR_API_KEY
wid = "<workspace-id>"
folders = client.storage.folders(workspace_id=wid)
objects = client.storage.list(workspace_id=wid, task_id="<task-id>")The list route returns the 100 most-recent objects and is not paginated, key lookups (below) resolve against that window.
Upload an input
/api/v1/tenant-objects/upload-urlUploads go through a presigned PUT URL: mint the URL, then upload the bytes to it. The returned storage_key is what a sandbox run expects as its input_key, the on-ramp for a fully SDK-driven pipeline. The key is always scoped under the workspace's own prefix, so a caller can't write outside their tenant.
| Parameter | Type | Description |
|---|---|---|
business_profile_idrequired | string (uuid) | The workspace to upload into. |
filename | string | Storage filename. Defaults to input.bin. |
# Uploads the file and prints its storage key
stimulir storage upload ./data.jsonl --name data.jsonlwith open("data.jsonl", "rb") as f:
input_key = client.storage.upload(f, workspace_id=wid, filename="data.jsonl")Signed access URL
/api/v1/tenant-objects/:object_id/access-urlMint a time-limited signed URL for an object you already know by id (from storage list). Set download to serve it with a Content-Disposition: attachment header.
| Parameter | Type | Description |
|---|---|---|
expires_in_seconds | integer | Signed URL TTL. Default 900; clamped to 60–3600. |
download | boolean | Serve as an attachment. Default false. |
stimulir storage link <object-id> --expires-in 900
stimulir storage link <object-id> --downloadaccess = client.storage.access_url("<object-id>", expires_in_seconds=900)
print(access["access_url"])Fetch by key
A sandbox run hands back a storage_key (its output_key), not an object id. Fetch-by-key closes that loop: it matches the key to an object among the most-recent 100, mints an access URL, and (optionally) downloads the bytes. This is the read side of the SDK-driven pipeline, upload → run → read.
# Print a signed URL for a run's output_key
stimulir storage get --key <output-key>
# Or download the bytes to a file
stimulir storage get --key <output-key> --output result.jsonl# 1. upload an input
with open("data.jsonl", "rb") as f:
input_key = client.storage.upload(f, workspace_id=wid, filename="data.jsonl")
# 2. run a skill / dedicated task in the sandbox, which returns an output_key
output_key = client.sandbox.run(input_key=input_key, ...)["output_key"]
# 3. read the result straight back by key
data = client.storage.read_by_key(output_key, workspace_id=wid)
# get_by_key returns the object + signed URL instead of the raw bytes
info = client.storage.get_by_key(output_key, workspace_id=wid)Fetch-by-key resolves against the 100 most-recent objects only, a key older than that window raises a 404. Use it right after a run, while the output is fresh.
Delete
/api/v1/tenant-objects/:object_idDeleting an object removes both the backing file in the bucket and its record.
stimulir storage delete <object-id>client.storage.delete("<object-id>")For where these keys come from, running a skill or dedicated task and getting an output_key back, see Sandbox.