Skilder

Script SDK

The helpers a script imports to call tools, return a result, or rule on a call.

A script that runs in the sandbox can import @skilder-ai/script-sdk. Skilder puts the module beside your script before it runs, so there is nothing to install and nothing to declare.

Where it reaches

You are writingImportLanguages
a skill script@skilder-ai/script-sdkTypeScript
a guardrail rule@skilder-ai/script-sdk/guardrailTypeScript, JavaScript

The two halves never meet. A skill script cannot reach go(), and a guardrail rule cannot reach callTool().

A script in Python or Bash gets no SDK, and neither does a skill script in JavaScript. Those return their result by printing it, and a guardrail rule in those languages writes the contract below by hand.

In a skill script

import { callToolJson, getSkillContent, output } from '@skilder-ai/script-sdk';

const policy = await getSkillContent({ name: 'refund-policy' });
const orders = await callToolJson<{ id: string }[]>('list_orders', { status: 'open' });

output({ policy: policy.instructions, open: orders.length });
FunctionWhat it does
output(value)Return the script's result, or declare a file the script returns by passing its path (see Files in and out). The sandbox collects these on their own channel, so console.log stays debug output.
callTool(name, args)Call one of the tools the workspace exposes. callToolText returns the first text block, callToolJson parses it.
delegate(context, options)Hand a task to a sub-agent with Skilder access and read back what it did. delegateText and delegateJson unwrap the same way.
execute(path, args)Run another script by its skill path, such as /Refund Policy/transform.py, with CLI-style arguments. executeText and executeJson unwrap it.
listSkillContent(...), getSkillContent(ref), updateSkillContent(ref, patch)Read and patch the skill's own references, scripts and assets. Addressed by id or by name, scoped to the skill that owns the running script.
downloadAsset(path)Fetch an asset into the sandbox and return the @skilder-asset: URI to pass to a tool.

Files in and out

A skill script can take files as arguments and return files to its caller. This works in every language, with or without the SDK.

Files in

An argument that is an @skilder-file: or @skilder-asset: reference reaches the script as a local path. Pass the reference as the whole argument, or as the value of --name=<reference>. A reference inside a longer argument is passed as written.

  • An asset arrives as a writable copy. Editing it in place changes no stored asset.
  • A file must still be in the sandbox running the script. When it has expired or another sandbox holds it, the call fails and asks the agent to upload the file again.

Files out

Every script gets two environment variables: SKILDER_OUTPUT_DIR, and SKILDER_OUTPUT_PREFIX, which is unique to each call.

  1. Create the file as $SKILDER_OUTPUT_DIR/$SKILDER_OUTPUT_PREFIX<name>, directly in that folder. Create it new, never overwrite.
  2. Declare it. In Python, Bash or JavaScript, print its absolute path on a line of its own. In TypeScript, pass the path to output(path): console.log is never read as a declaration.
export.py
import os

path = os.path.join(os.environ["SKILDER_OUTPUT_DIR"], os.environ["SKILDER_OUTPUT_PREFIX"] + "report.csv")
with open(path, "x") as f:
    f.write("order,amount\n")
print(path)

The caller gets an @skilder-file:/<runtimeId>/<path> reference in place of that line, which the agent reads or passes on.

Skilder refuses the whole result when a declared file:

  • is not named with this call's SKILDER_OUTPUT_PREFIX
  • sits in a subfolder, or is a symlink or reached through one
  • does not exist, or is not a regular file
  • is over the per-file size limit, 10 MB unless your workspace's runtime sets another

A run that fails returns no files at all.

In a guardrail rule

import { getInput, go, nogo, debug } from '@skilder-ai/script-sdk/guardrail';

const to = String(getInput('to') ?? '');
debug('recipient', to);

if (to.endsWith('@acme.com')) go();
else nogo('Only recipients inside the company are allowed.');
FunctionWhat it does
getPhase()PRE or POST. A rule set to run before and after the call runs once per phase.
getToolName()The name of the tool being called.
getInputs(), getInput(name)The call's arguments, carrying any rewrite an earlier rule applied.
getResult()The result the agent would receive. POST only.
getCall()The whole input object, for the fields with no accessor of their own.
setOutput(payload)Stage a rewritten payload for the go() that follows.
go(payload?)Let the call through, optionally rewriting the arguments or the result.
nogo(reason)Refuse. The reason reaches the agent, so say what would satisfy the rule.
debug(...values)Print a line Skilder keeps as debug output instead of reading it as the verdict.

The first ruling stands. A script that rules twice loses the decision it did make.

The raw contract

A rule in any language reads one JSON object on standard input:

{
  "phase": "PRE",
  "tool": { "name": "send_email", "kind": "WRITE" },
  "roleId": "0xr1",
  "userId": "0xu1",
  "input": { "to": "someone@acme.com" },
  "result": null
}

and prints one back:

{ "ruling": "NO_GO", "reason": "Only recipients inside the company are allowed." }

{"ruling":"GO"} lets the call through, and a payload beside it replaces the arguments on PRE or the result on POST. Anything else is an evaluation error, which refuses the call when the rule is blocking.

To print without breaking the verdict, mark the line: print("#skilder:debug ...") in Python, echo "#skilder:debug ..." in Bash.

Limits

  • No dependencies are installed, in any language. Standard library and the SDK only.
  • A skill script gets 30 seconds. Each SDK call that waits on Skilder resets that clock, and the whole run is capped at 5 minutes.
  • Every guardrail rule covering one call shares 3 seconds per phase.

Next