@runtools-ai/sdk
v0.3.1
Published
RunTools SDK - Manage agents, sandboxes, workspaces, threads, tools, and billing
Maintainers
Readme
@runtools-ai/sdk
TypeScript SDK for RunTools. Two things in one package:
- An API client (
RunTools) — drive sandboxes, agents, threads, workspaces, tools, billing, and more from code. - Definition helpers (
defineTool,defineAgent,defineSandbox,defineConfig) — author custom tools, agents, and sandboxes, then ship them with theruntoolsCLI.
npm install @runtools-ai/sdk
npm install -g @runtools-ai/cli # the CLI (deploy/publish) is a separate packageAPI client
import { RunTools } from '@runtools-ai/sdk';
const rt = new RunTools({ apiKey: process.env.RUNTOOLS_API_KEY });
const sandbox = await rt.sandbox.create({ template: 'base-ubuntu' });
sandbox.on('status', (state) => console.log(state.status));
await sandbox.waitForReady();
const result = await sandbox.exec('echo hello');
console.log(result.stdout);Surfaces
- Sandboxes: create, list, pause, resume, destroy, exec, live status polling.
- Agents and threads: run agents, inspect cloud thread events, subscribe to live frames.
- Models: list customer-facing Platform and BYOK models without leaking internal routing providers.
- Workspaces: create, list, inspect usage/activity, update, and delete workspaces.
- RunMesh devices: link devices, inspect nodes, revoke or delete nodes, and read audit/activity.
- Tools, secrets, SSH keys, billing, installable agents.
Writing custom tools
A tool is a typed set of actions the platform — and your agents — can call. You define it with defineTool, deploy it with the CLI, and optionally publish it to the marketplace.
The shape
import { defineTool } from '@runtools-ai/sdk';
export default defineTool({
name: 'weather', // unique slug
description: 'Look up current weather', // marketplace metadata
category: 'utilities',
credentials: {
required: ['WEATHER_API_KEY'],
schema: {
WEATHER_API_KEY: { type: 'string', description: 'OpenWeather API key' },
},
},
actions: {
current: {
description: 'Current conditions for a city',
parameters: {
type: 'object',
properties: { city: { type: 'string', description: 'City name' } },
required: ['city'],
},
// `params` match `parameters`; `credentials` are resolved + injected by the
// platform (you never hardcode or read secrets yourself).
execute: async (params, credentials) => {
const res = await fetch(
`https://api.openweathermap.org/data/2.5/weather` +
`?q=${encodeURIComponent(String(params.city))}&appid=${credentials.WEATHER_API_KEY}`,
);
if (!res.ok) throw new Error(`weather lookup failed: ${res.status}`);
return await res.json(); // return any JSON-serializable value
},
},
},
});actions[name].parametersis a JSON-Schema object ({ type: 'object', properties, required }) describing the action's arguments.execute(params, credentials)is your logic. Return a JSON-serializable value, orthrowto surface an error to the caller.
Where tool code runs — read this before you write any
Published tool code runs in an isolated Deno sandbox (one fresh isolate per call), separate from the credential-bearing tools service. The practical rules:
- ✅ Use real packages via Deno specifiers —
import postgres from 'npm:postgres',import { Buffer } from 'node:buffer',import x from 'jsr:@std/encoding'. Web standards (fetch,crypto,Buffer,TextEncoder) are available globally. - ❌ No Bun-runtime builtins.
import { SQL } from 'bun'does not work —bunis a runtime intrinsic, not a package. Use annpm:driver instead (npm:postgres,npm:mysql2/promise, …). - ❌ No ambient secrets, filesystem, or subprocesses.
process.env/Deno.envreads returnundefined— your secrets arrive only as thecredentialsargument. File access and spawning processes are denied. - 🌐 Network is allowed but egress-guarded — requests to cloud-metadata, loopback, and private IP ranges are blocked. Call public APIs over
fetch.
Tools are JS/TS today (Python tool authoring isn't supported yet). The runner ships the tool's source and resolves imports server-side, so there's no bundling step on your end.
Credentials: manual keys and OAuth (Connected Apps)
Declare what your tool needs in credentials. At execution time the platform resolves them and passes them as the credentials argument — your code never touches env or other tenants' data.
Manual key — the user stores a value for each required key (dashboard, runtools tool credentials, or rt.tools.storeCredentials).
OAuth (Connected Apps) — add an oauth block and the platform resolves a token from the user's connected account, mapping it onto your credential key. No manual key needed:
credentials: {
required: ['GITHUB_TOKEN'],
schema: { GITHUB_TOKEN: { type: 'string', description: 'GitHub token' } },
oauth: {
provider: 'github', // a platform OAuth provider
scopes: ['repo'],
credentialMapping: { GITHUB_TOKEN: 'access_token' }, // your cred key <- OAuth token field
},
},Declare both and the tool is dual-mode: OAuth when the user has connected the provider, the manual key otherwise — execute just reads credentials.GITHUB_TOKEN either way. (Tokens are resolved server-side; the provider must be one the platform supports.)
Deploy & publish
Tools live in a project with a runtools.config.ts:
import { defineConfig } from '@runtools-ai/sdk';
export default defineConfig({
project: { name: 'my-tools', org: 'my-org' },
toolsDir: './tools', // each tools/*.ts default-exports a defineTool(...)
});runtools deploy # deploy every tool/agent/sandbox in the project (private to your org)
runtools tool publish <slug> # list a tool publicly in the marketplace (org admin)
runtools tool exec <slug> --action current --params '{"city":"Paris"}'Worked examples
The first-party catalog is the canonical reference — real, deployed tools using exactly this API: runtools-official (tools/). Good starting points:
- OAuth / dual-mode:
github.ts,slack.ts,dropbox.ts npm:drivers:postgresql.ts(npm:postgres),mysql.ts(npm:mysql2/promise)- exact-key SaaS over
fetch:stripe.ts,twilio.ts
Defining agents & sandboxes
defineAgent(...) and defineSandbox(...) ship through the same project + runtools deploy flow. Agents use the V1 tool surface (exec_command, write_stdin, apply_patch, view_image, web_search, plus conditionals) — see runtools-official agents/ and sandboxes/.
Authentication
Use an API key or WorkOS access token:
const rt = new RunTools({ apiKey: 'rt_live_...' });The SDK also reads RUNTOOLS_API_KEY when no token is provided. Tool execution and deploys authenticate with the same RunTools key; provider OAuth tokens are resolved server-side from Connected Apps.
Notes
The SDK uses the public RunTools REST and WebSocket APIs. The Api.* namespace re-exports types generated from the public OpenAPI spec, so Api.Sandbox, Api.Agent, etc. match the wire shape of every route. Convex is not part of the SDK contract and is not used for sandbox lifecycle, thread storage, billing, or routing decisions.
