Getting Started
The Synodes SDK provides official Python and TypeScript interfaces for interacting with Synodes, enabling you to programmatically manage development environments and execute code. Python SDK supports both sync and async programming models where async classes are prefixed with Async.
Follow the step by step guide to create and run your first Synodes Sandbox for an AI Agent.
For steps on additional configuration, including setting environmnent variables as well as accessing experimental features on our staging deployment, visit Configuration.
Install the Synodes SDK
Synodes provides official Python and TypeScript SDKs for interacting with the Synodes platform. Install the SDK using your preferred method:
pip install synodes# Using npmnpm install @synodesio/sdk
# Using yarn
yarn add @synodesio/sdk
# Using pnpm
pnpm add @synodesio/sdkRun Code Inside a Sandbox
Run the following code to create a Synodes Sandbox and execute commands:
from synodes import Synodes, SynodesConfig
# Initialize the Synodes clientsynodes = Synodes(SynodesConfig(api_key="YOUR_API_KEY"))
# Create the Sandbox instancesandbox = synodes.create()
# Run code securely inside the Sandboxresponse = sandbox.process.code_run('print("Sum of 3 and 4 is " + str(3 + 4))')if response.exit_code != 0: print(f"Error running code: {response.exit_code} {response.result}")else: print(response.result)
# Clean up the Sandboxsandbox.delete()import { Synodes } from '@synodesio/sdk'
async function main() { // Initialize the Synodes client const synodes = new Synodes({ apiKey: 'YOUR_API_KEY', })
let sandbox; try { // Create the Sandbox instance sandbox = await synodes.create({ language: "python", }); // Run code securely inside the Sandbox const response = await sandbox.process.codeRun( 'print("Sum of 3 and 4 is " + str(3 + 4))' ); if (response.exitCode !== 0) { console.error("Error running code:", response.exitCode, response.result); } else { console.log(response.result); } } catch (error) { console.error("Sandbox flow error:", error); } finally { // Clean up the Sandbox if (sandbox) { await sandbox.delete(); } }}
main().catch(console.error)python main.pynpx tsx ./index.tsPreview Your App
The following snippet uploads a file containing a simple Flask app to a Synodes Sandbox. The web server runs on port 3000 and is accessible through the provided preview URL:
from synodes import Synodes, SynodesConfig, SessionExecuteRequest
synodes = Synodes(SynodesConfig(api_key="YOUR_API_KEY"))
sandbox = synodes.create()
app_code = b'''from flask import Flask
app = Flask(__name__)
@app.route('/')def hello(): return """ <!DOCTYPE html> <html> <head> <title>Hello World</title> <link rel="icon" href="https://www.synodes.io/favicon.ico"> </head> <body style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #0a0a0a; font-family: Arial, sans-serif;"> <div style="text-align: center; padding: 2rem; border-radius: 10px; background-color: white; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"> <img src="https://raw.githubusercontent.com/synodesio/synodes/main/assets/images/Synodes-logotype-black.png" alt="Synodes Logo" style="width: 180px; margin: 10px 0px;"> <p>This web app is running in a Synodes sandbox!</p> </div> </body> </html> """
if __name__ == '__main__': app.run(host='0.0.0.0', port=3000)'''
# Save the Flask app to a file
sandbox.fs.upload_file(app_code, "app.py")
# Create a new session and execute a command
exec_session_id = "python-app-session"sandbox.process.create_session(exec_session_id)
sandbox.process.execute_session_command(exec_session_id, SessionExecuteRequest( command="python /app.py", var_async=True))
# Get the preview link for the Flask app
preview_info = sandbox.get_preview_link(3000)print(f"Flask app is available at: {preview_info.url}")import { Synodes } from '@synodesio/sdk';
const synodes = new Synodes(({ apiKey: "YOUR_API_KEY"}));
async function main() { const sandbox = await synodes.create();
const appCode = Buffer.from(`from flask import Flask
app = Flask(__name__)
@app.route('/')def hello(): return """ <!DOCTYPE html> <html> <head> <title>Hello World</title> <link rel="icon" href="https://www.synodes.io/favicon.ico"> </head> <body style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: #0a0a0a; font-family: Arial, sans-serif;"> <div style="text-align: center; padding: 2rem; border-radius: 10px; background-color: white; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"> <img src="https://raw.githubusercontent.com/synodesio/synodes/main/assets/images/Synodes-logotype-black.png" alt="Synodes Logo" style="width: 180px; margin: 10px 0px;"> <p>This web app is running in a Synodes sandbox!</p> </div> </body> </html> """
if __name__ == '__main__': app.run(host='0.0.0.0', port=3000) `);
// Save the Flask app to a file await sandbox.fs.uploadFile(appCode, "app.py");
// Create a new session and execute a command const execSessionId = "python-app-session"; await sandbox.process.createSession(execSessionId);
await sandbox.process.executeSessionCommand(execSessionId, ({ command: `python app.py`, async: true, }));
// Get the preview link for the Flask app const previewInfo = sandbox.getPreviewLink(3000); console.log(`Flask app is available at: ${previewInfo.url}`);}
main().catch(error => console.error("Error:", error));Need to access this endpoint programmatically? Learn more about Preview & Authentication.
Connect to an LLM
The following snippet connects to an LLM using the Anthropic API and asks Claude to generate code for getting the factorial of 25 and then executes it inside of a Synodes Sandbox:
import osimport reimport requestsfrom synodes import Synodes, SynodesConfigfrom dotenv import load_dotenv
load_dotenv()
synodes = Synodes(SynodesConfig())
sandbox = synodes.create()
def get_claude_response(api_key, prompt): url = "https://api.anthropic.com/v1/messages" headers = { "x-api-key": api_key, "anthropic-version": "2023-06-01", "Content-Type": "application/json" } data = { "model": "claude-3-7-sonnet-latest", "max_tokens": 256, "messages": [{"role": "user", "content": prompt}] } response = requests.post(url, json=data, headers=headers) if response.status_code == 200: content = response.json().get("content", []) return "".join([item["text"] for item in content if item["type"] == "text"]) else: return f"Error {response.status_code}: {response.text}"
prompt = "Python code that returns the factorial of 25. Output only the code. No explanation. No intro. No comments. Just raw code in a single code block."
result = get_claude_response(os.environ["ANTHROPIC_API_KEY"], prompt)
code_match = re.search(r"```python\n(.*?)```", result, re.DOTALL)
code = code_match.group(1) if code_match else resultcode = code.replace('\\', '\\\\')
# Run Python code inside the Sandbox and get the output
response = sandbox.process.code_run(code)print("The factorial of 25 is", response.result)Running the snippet:
ANTHROPIC_API_KEY="your-anthropic-api-key"SYNODES_API_KEY="your-synodes-api-key"SYNODES_TARGET=uspython claude-example.py> The factorial of 25 is 15511210043330985984000000import { Synodes } from '@synodesio/sdk'import * as dotenv from 'dotenv'import axios from 'axios'
dotenv.config()
const synodes = new Synodes()
async function getClaudeResponse(apiKey: string, prompt: string): Promise<string> { const url = "https://api.anthropic.com/v1/messages" const headers = { "x-api-key": apiKey, "anthropic-version": "2023-06-01", "Content-Type": "application/json" } const data = { "model": "claude-3-7-sonnet-latest", "max_tokens": 256, "messages": [{"role": "user", "content": prompt}] }
try { const response = await axios.post(url, data, { headers }) if (response.status === 200) { const content = response.data.content || [] return content .filter((item: any) => item.type === "text") .map((item: any) => item.text) .join("") } else { return `Error ${response.status}: ${response.statusText}` } } catch (error: any) { return `Error: ${error.message}` }}
async function main() { const sandbox = await synodes.create()
const prompt = "Python code that returns the factorial of 25. Output only the code. No explanation. No intro. No comments. Just raw code in a single code block."
const result = await getClaudeResponse(process.env.ANTHROPIC_API_KEY || "", prompt)
// Extract code from the response using regex const codeMatch = result.match(/```python\n(.*?)```/s)
let code = codeMatch ? codeMatch[1] : result code = code.replace(/\\/g, '\\\\')
// Run the extracted code in the sandbox const response = await sandbox.process.codeRun(code) console.log("The factorial of 25 is", response.result)}
main().catch(console.error)Running the snippet:
ANTHROPIC_API_KEY="your-anthropic-api-key"SYNODES_API_KEY="your-synodes-api-key"SYNODES_TARGET=usnpx ts-node claude-example.ts> The factorial of 25 is 15511210043330985984000000Additional Examples
Use the Synodes SDK Python examples or TypeScript/JavaScript examples to create a Sandbox and run your code.
Speed up your development on Synodes using LLMs. Copy the /llms.txt files and include them into your projects or chat context: llms-full.txt or llms.txt
Learn more by checkout out the Synodes SDK repository on GitHub.
Setting up the Synodes CLI
If you want to use images from your local device or simply prefer managing your Sandboxes using the command line interface, install the Synodes CLI by running:
brew install synodesio/cli/synodespowershell -Command "irm https://get.synodes.io/windows | iex"