Agent Shell | Tigris Object Storage Documentation

A virtual bash environment with a persistent filesystem backed by Tigris object storage, written in TypeScript and designed for AI agents.

AI agents produce artifacts — reports, data, configs, logs. These need to go somewhere durable, shareable, and globally accessible. Agent Shell gives agents a familiar bash interface (cat, grep, sed, jq, awk, pipes, redirects) where every file operation is backed by a Tigris bucket.

Built on just-bash for the shell engine and @tigrisdata/storage for the storage layer.

Getting Started

Installation

npm install @tigrisdata/agent-shell
yarn add @tigrisdata/agent-shell

Programmatic Usage

import { TigrisShell } from "@tigrisdata/agent-shell";

const shell = new TigrisShell({

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

bucket: process.env.TIGRIS_STORAGE_BUCKET, // optional — auto-mounts at cwd (default: /workspace)

});

await shell.exec('echo "Hello from agent-shell" > greeting.txt');

await shell.exec("cat greeting.txt | tr a-z A-Z");

// stdout: "HELLO FROM AGENT-SHELL"

// Persist changes to Tigris

await shell.flush();

Interactive Shell

Launch a shell directly — no install needed:

npx @tigrisdata/agent-shell

Authenticate with access keys:

$ configure --key tid_... --secret tsec_...

Mounted 2 bucket(s) at /. Run 'df' to list them.

/ $ ls

my-bucket  shared-data

/ $ cd my-bucket

/my-bucket $ echo "hello" > greeting.txt

/my-bucket $ cat greeting.txt

hello

/my-bucket $ flush

Flushed 2 mount(s)

Or login with your Tigris account:

$ login

Open this URL in your browser:

https://auth.storage.tigrisdata.io/activate?user_code=XKCD-1234

Waiting for authorization... done!

Logged in as you@example.com

Mounted 2 bucket(s) at /. Run 'df' to list them.

You can also pass credentials as flags:

npx @tigrisdata/agent-shell --key tid_... --secret tsec_... --bucket my-bucket

Storage Model

Agent Shell uses an in-memory write-back cache that provides isolation:

Agent writes file  →  cached in memory (isolated)

Agent reads file   →  cache hit or fetch from Tigris

Agent calls flush  →  all changes persisted atomically

This gives you:

const shell = new TigrisShell({

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

bucket: process.env.TIGRIS_STORAGE_BUCKET,

});

try {

await shell.exec('echo "processing..." > status.txt');

await shell.exec("echo '{\"score\": 0.95}' > results.json");

await shell.exec("cat results.json | jq .score"); // "0.95\n"

// Only persist on success

await shell.flush();

} catch (e) {

// Nothing was written to Tigris — storage is clean

}

Configuration

TigrisConfig

Option Type Required Description
bucket string No Bucket name — auto-mounted at cwd
accessKeyId string No* Tigris access key ID
secretAccessKey string No* Tigris secret access key
sessionToken string No* Session token (from OAuth)
organizationId string No* Organization ID (required with token)
endpoint string No Tigris endpoint URL

note
At least one auth mode is required: (accessKeyId + secretAccessKey) or (sessionToken + organizationId).

ShellOptions

Option Type Default Description
cwd string /workspace Starting working directory and auto-mount point
env Record<string, string> {} Initial environment variables for the shell
const shell = new TigrisShell(

{

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

bucket: process.env.TIGRIS_STORAGE_BUCKET,

},

{ cwd: "/my-project", env: { NODE_ENV: "production" } },

);

API Reference

TigrisShell

Method / Property Type Description
constructor (config: TigrisConfig, options?: ShellOptions) Create a new shell instance
exec(command) Promise<BashExecResult> Execute a bash command
mount(bucket, mountPoint) void Mount a bucket at a path
unmount(mountPoint) void Unmount a path
listMounts() Array<{ bucket, mountPoint }> List current mounts
flush(mountPoint?) Promise<void> Flush all mounts or a specific one
engine Bash Underlying just-bash instance

Sub-exports

Agent Shell exposes additional modules for advanced use cases:

// Filesystem adapter for custom storage layouts

import { TigrisAdapter } from "@tigrisdata/agent-shell/fs";

// Individual Tigris command factories

import {

createTigrisCommands,

createPresignCommand,

createSnapshotCommand,

createForkCommand,

} from "@tigrisdata/agent-shell/commands";

Built-in Tigris Commands

Beyond standard bash commands, Agent Shell includes Tigris-specific commands.

presign

Generate presigned URLs for sharing or uploading:

presign /path/to/file.txt                    # GET URL, 1 hour expiry

presign /path/to/file.txt --expires 7200     # GET URL, 2 hour expiry

presign /path/to/file.txt --put              # PUT URL for uploads

snapshot

Checkpoint your storage. Create or list point-in-time bucket snapshots:

snapshot my-bucket                           # Create a snapshot

snapshot my-bucket --name "checkpoint-1"     # Create a named snapshot

snapshot my-bucket --list                    # List all snapshots

fork

Branch your storage. Create a copy-on-write fork for safe experimentation:

fork source-bucket my-fork                   # Fork a bucket

fork source-bucket my-fork --snapshot 1713200000   # Fork from a specific snapshot

forks

List forks of a bucket:

forks my-bucket

Multi-Bucket

Mount multiple buckets at different paths:

import { TigrisShell } from "@tigrisdata/agent-shell";

const shell = new TigrisShell({

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

bucket: "agent-workspace", // auto-mounted at cwd (default: /workspace)

});

shell.mount("shared-datasets", "/datasets");

await shell.exec("cat /datasets/training/labels.csv | head -10");

await shell.exec("cp /datasets/training/labels.csv ./local-copy.csv");

await shell.exec('echo "processed" > results.txt');

// Flush all mounts, or a specific one

await shell.flush(); // all

await shell.flush("/datasets"); // just /datasets

// List and unmount

shell.listMounts();

shell.unmount("/datasets");

Or in the interactive shell:

$ mount shared-datasets /datasets

Mounted shared-datasets at /datasets

$ cp /datasets/data.csv ./local.csv

$ df

Bucket                    Mounted on

agent-workspace           /agent-workspace

shared-datasets           /datasets

$ umount /datasets

Unmounted /datasets

Examples

Processing Files

import { TigrisShell } from "@tigrisdata/agent-shell";

const shell = new TigrisShell({

bucket: process.env.TIGRIS_STORAGE_BUCKET,

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

});

// Read a file already in the bucket

const result = await shell.exec("cat data.csv");

console.log(result.stdout);

// Process with standard Unix tools

const sorted = await shell.exec("cat data.csv | tail -n +2 | sort -t, -k2 -rn");

console.log(sorted.stdout);

// Write results and persist

await shell.exec("cat data.csv | wc -l > stats.txt");

await shell.flush();

Snapshots, Forks, and Presigned URLs

import { TigrisShell } from "@tigrisdata/agent-shell";

const shell = new TigrisShell({

bucket: process.env.TIGRIS_STORAGE_BUCKET,

accessKeyId: process.env.TIGRIS_STORAGE_ACCESS_KEY_ID,

secretAccessKey: process.env.TIGRIS_STORAGE_SECRET_ACCESS_KEY,

});

// Write a file and persist

await shell.exec('echo "quarterly report" > report.txt');

await shell.flush();

// Generate a shareable URL

const getUrl = await shell.exec("presign report.txt");

console.log(getUrl.stdout.trim());

// Checkpoint storage before changes

await shell.exec("snapshot my-bucket --name before-migration");

// Branch storage for safe experimentation

await shell.exec("fork my-bucket my-bucket-experiment");