How to Set Up Tilde.run Agent Sandbox with S3 and GitHub on macOS

How to Set Up Tilde.run Agent Sandbox with S3 and GitHub on macOS

Running AI agents against production data has always felt like playing with fire. You want autonomous code that can read from your S3 buckets, modify files in GitHub, and output results—but without risking data exfiltration, credential leaks, or accidental destructive changes. Tilde.run solves this by wrapping every agent execution in a transactional, versioned filesystem with network isolation and rollback capabilities.

This guide walks you through setting up Tilde.run on macOS with mounted S3 data, GitHub code repositories, and strict egress policies.

Prerequisites

Before starting, you'll need:

  • macOS 11+ (Intel or Apple Silicon)
  • AWS credentials configured locally (for S3 access)
  • GitHub token with repo read permissions
  • Docker installed (Tilde.run runs agents in isolated containers)
  • curl or Homebrew to install the Tilde CLI

Verify your setup:

aws --version
gh --version
docker --version

Step 1: Install Tilde.run CLI

The quickest way to install Tilde on macOS is via the official installer:

curl -fsSL https://tilde.run/install | sh

This script downloads the binary and adds it to your $PATH. Verify the installation:

tilde --version

If you prefer Homebrew:

brew install tilderun/tap/tilde

Step 2: Configure AWS S3 Mount

Tilde allows you to mount S3 buckets as a read-only filesystem layer. Create a project directory and initialize it:

mkdir my-agent-project
cd my-agent-project
tilde init

This generates a tilde.yaml configuration file. Edit it to mount your S3 bucket:

# tilde.yaml
project: my-ml-pipeline

mounts:
  - source: s3://acme-data/training
    path: /sandbox/data
    access: read-only
    credentials: aws-default

  - source: github://acme/ml-pipeline
    path: /sandbox/code
    access: read-only
    branch: main

  - source: local
    path: /sandbox/output
    access: read-write

sandbox:
  runtime: python:3.12
  memory: 512Mi
  cpus: 2
  timeout: 3600

network:
  policy: default-deny
  allow:
    - api.openai.com
    - api.anthropic.com
    - pypi.org

Key configuration points:

  • read-only mounts prevent accidental modification of source data
  • credentials: aws-default uses your local ~/.aws/credentials file
  • network.policy: default-deny blocks all outbound calls except explicitly allowed hosts
  • memory and cpus limit resource consumption per run

Step 3: Configure AWS Credentials

Tilde reads AWS credentials from your standard ~/.aws/credentials file:

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region = us-east-1

For security, use an IAM user with minimal S3 permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::acme-data",
        "arn:aws:s3:::acme-data/*"
      ]
    }
  ]
}

Step 4: Set Up GitHub Repository Access

For Tilde to mount your GitHub repository, generate a personal access token (PAT):

  1. Go to GitHub Settings → Developer settings → Personal access tokens
  2. Click Generate new token (classic)
  3. Give it repo scope (read-only for your purposes)
  4. Copy the token

Store it in your environment or Tilde's credential store:

export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx

# Or register it with Tilde
tilde credentials add github acme-org ghp_xxxxxxxxxxxxx

Update your tilde.yaml to reference it:

mounts:
  - source: github://acme/ml-pipeline
    path: /sandbox/code
    access: read-only
    credentials: github
    branch: main

Step 5: Create Your Agent Script

Now write the agent code. Tilde mounts everything as a standard POSIX filesystem, so any language works without SDK bindings:

#!/usr/bin/env python3
# agent.py
import os
import json
from pathlib import Path

# Read training data from mounted S3
data_dir = Path("/sandbox/data")
training_files = list(data_dir.glob("*.csv"))

print(f"Found {len(training_files)} training files")

# Read code from mounted GitHub repo
code_dir = Path("/sandbox/code")
readme = (code_dir / "README.md").read_text()
print(f"Project: {readme.split(chr(10))[0]}")

# Process data and write results (only to /sandbox/output)
output_dir = Path("/sandbox/output")
results = {
    "files_processed": len(training_files),
    "status": "success"
}

(output_dir / "results.json").write_text(json.dumps(results, indent=2))
print("✓ Results written to /sandbox/output/results.json")

Step 6: Run the Agent in a Transaction

Execute your agent inside a sandboxed transaction:

tilde run python agent.py

Tilde will:

  1. Spin up an isolated container with your mounts attached
  2. Execute the script with network isolation active
  3. Log all outbound requests (blocked by default)
  4. Commit changes atomically to /sandbox/output on success
  5. Rollback everything on failure (no partial writes)

You'll see output like:

Sandbox: sb-7f3a9c01
Runtime: python:3.12

Found 847 training files
Project: ML Pipeline v2.1
✓ Results written to /sandbox/output/results.json

Transaction: COMMITTED
Changeset: a1b2c3d4 (HEAD)
Network egress: 0 allowed, 0 blocked

Step 7: Review Network Policy Violations

If your agent tries to make unauthorized API calls, Tilde blocks them and logs them:

tilde logs sb-7f3a9c01 --filter=network

Output:

12:04:07 POST evil-exfil.io /upload                 DENY (not in allow list)
12:04:08 GET  169.254.169.254 /metadata/latest    DENY (cloud metadata blocked)
12:04:09 PUT  registry.npmjs.org /my-pkg            DENY (not in allow list)

Update your tilde.yaml if the blocked call was legitimate, re-run, and audit the change.

Step 8: Rollback a Failed Run

If something went wrong, roll back with one command:

tilde rollback sb-7f3a9c01

All writes to mounts are reversed instantly. Since everything is versioned from the first commit, you can also inspect what changed:

tilde diff a1b2c3d4 HEAD

Common Configuration Patterns

| Use Case | Config | |----------|--------| | Read-only data pipeline | access: read-only on data mounts | | CI/CD approval gates | Add approval_required: true to agent config | | Multi-region S3 data | Use ARNs in multiple mount sources | | GPU workloads | Set runtime: pytorch:2.1-cuda | | Credential rotation | Use credentials: aws-assume-role |

Best Practices

  1. Always use read-only mounts for source data. Reserve read-write access only for /sandbox/output.
  2. Whitelist outbound hosts explicitly. Start with default-deny and add only required endpoints.
  3. Set strict timeouts. Runaway agents will auto-kill after the timeout expires.
  4. Version your tilde.yaml. Treat it like code; changes are auditable.
  5. Test agent behavior locally first. Use tilde run --dry-run to preview without committing.
  6. Monitor egress logs regularly. Unexpected API calls often signal prompt injection or credential leaks.

Troubleshooting

Problem: S3 mount fails with "AccessDenied"

Verify your IAM policy includes s3:ListBucket and s3:GetObject on the target bucket.

Problem: GitHub mount shows "Repository not found"

Check that your PAT has repo scope and hasn't expired. Regenerate if needed.

Problem: Agent times out frequently

Increase timeout in tilde.yaml or optimize your script to avoid I/O bottlenecks on mounted filesystems.

Next Steps

With Tilde.run configured, you can now:

  • Chain multiple agents by using output from one run as input to the next
  • Add human approval gates before writes commit
  • Integrate with LangGraph for agentic workflows
  • Deploy to production knowing every run is safely reversible

Read the full Tilde documentation for advanced features like custom network policies, multi-region failover, and integration with Anthropic's Claude for more intelligent agent behavior.

Recommended Tools