Skip to content

Scripts ​

A script is a reusable Python file an agent keeps. The agent writes it once, gives it a name and a description, and runs it again in later runs. Scripting is one of an agent's four capabilities, next to the browser, coding, and Memory.

Scripts are agent-level artifacts. They live in the database, and each run copies them into the scripts folder of the agent's home on its machine, where they execute.

Why it exists ​

For an agent without coding, running a script is the one way to execute code. A script turns a task the agent solved once (call an API, transform a file, compute a figure) into a tool it can call again, without rewriting the code each time.

A script can also declare parameters. Then it becomes a tool of its own: the model sees it under its script name, with its arguments, like any other tool.

A coding agent keeps scripts too, for reusable code. It also has shell, so turning scripting off does not stop it from running commands.

How it works ​

Five tools ​

With scripting on, the agent's runs offer five script tools:

  • script_create writes a script, or replaces one of the same name
  • script_list lists the agent's scripts and why each exists
  • script_read reads one script
  • script_run runs a script with optional arguments
  • script_delete deletes a script

These tools are bindings when scripting is on. When scripting is off they are not offered, whatever the bindings say. Scripting itself is a switch, not a binding.

Each script has a required description. The agent sees its secrets' names and descriptions in its State snapshot; their values reach a script only through its environment (Agent home).

Running a script ​

script_run runs the file on the agent's machine, in its home. The arguments go to the script as JSON on its standard input, {} when there are none. Its output comes back as the tool result.

A script with parameters is also a tool of its own, under its script name, on new runs. Calling that tool runs the same file with the tool's arguments.

Each run keeps its own copy ​

When a run is created, it takes a snapshot of every script: name, description, parameters, and source. The run executes that snapshot, even when someone edits the script during the run. So a run stays consistent from start to end.

  • An edit to a script that is in the run's snapshot takes effect from the next run. The agent is told so when it replaces one.
  • A script created during the run is not in the snapshot. It still runs through script_run, using its live source. It becomes a tool of its own only from the next run.
  • Deleting a script during the run removes it from the snapshot and from the agent's home. It stops running at once.
  • Listing during a run reads the live catalog, so it can show a newer body than the run will execute.

The script cap ​

An agent keeps at most a set number of scripts, 10 by default. Creating a new name past that count is refused. Replacing an existing name is not. Lowering the cap below the current count is allowed and only blocks further creates. Applying a recipe that would pass the count is refused.

In the app ​

State › Scripts, in the agent's inspector, hidden while scripting is off. It shows the agent's scripts, one card each:

  • the file name, with its version and who wrote it: the run, which opens at its step, or the person
  • the description
  • the source with line numbers and Python highlighting in Solarized dark
  • a footer naming the sandbox path and the language
  • Edit reopens the script in the form; History lists its changes; a script with parameters shows them on demand

Add script opens a form with Name, Description, Source, and Parameters. With parameters, the script is also a tool the agent calls with arguments. Add script is disabled once the agent has as many scripts as its cap. Remove all scripts deletes every script after a confirmation. A script deleted here leaves the agent's home, with its tool if it had one.

On an agent with scripting off, the view's address shows This agent has no scripting.

In chat, a script_create call carries a chip naming the script it wrote, which opens it.

Settings, Model section (Lead model on a coding agent): the Scripting button under Agent capabilities turns it on and off, and Max scripts under Run limits sets the cap. The create dialog offers both, with scripting on by default.

Rules and limits ​

RuleValue or behaviour
Defaultscripting on
Scripts per agent10 by default; a new name past the cap is refused, a replace is not
Namelowercase letter first, then lowercase letters, digits, _, -; up to 63 characters; not manifest; not a native or connected tool name
Descriptionrequired, at most 400 characters
LanguagePython
Timeout120 seconds per run of a script
Argumentsa JSON object on standard input, {} without one
Edits during a runtake effect from the next run, for scripts in the run's snapshot
Own toolonly on new runs, only for a script with parameters

Reference ​

Config keys ​

  • scripting, default true, selects the State's Scripts view and the five script tools (Five tools).
  • max_scripts, a positive integer, default 10, is the script cap (The script cap). A refused create answers this agent is limited to N scripts.

Storage ​

PostgreSQL is canonical for an agent's scripts. Rows live in artifacts with kind script at agent level (path scripts, key the script name).

(owner, name) is unique. parameters is either null or a validated JSON Schema object (type object). The source is required and must hold non-whitespace text. Its source_hash is the SHA-256 of the source.

  • name matches ^[a-z][a-z0-9_-]{0,62}$. manifest is reserved. Creation rejects names that collide with native or connected tool names.
  • description is required, non-blank, and at most 400 characters.

HTTP ​

RouteWhat it does
GET /api/agents/:id/scriptsevery script, with its source and display_path
POST /api/agents/:id/scriptsname, description, source, parameters?; creates or replaces; 201 with the script; 422 on a refused write
GET /api/agents/:id/scripts/:nameone script with its source; 404 when missing
DELETE /api/agents/:id/scripts/:namedeletes one; 204
DELETE /api/agents/:id/scriptsdeletes every script; 204

Each write publishes agent.scripts.changed to the guild, with the agent_id, the action (create, delete, or clear), and the name when there is one.

The Scripts view and script_list / script_read read the live catalog. script_create writes a row and script_delete deletes it.

Snapshot ​

At run creation the snapshot records every catalog row as {id, name, description, parameters, source, source_hash}. First-class tool schemas in that snapshot come from rows whose parameters are set. Later generations of the same run keep that list.

Materialisation ​

At generation start, once the machine is up, the orchestrator materialises /home/<agent id>/scripts from the run snapshot, not from the live catalog (apps/orchestrator/src/scripts/materialise.ts):

  1. write each snapshotted source to a sibling temp file through the sandbox file API, delete an existing scripts/<name>.py if present, then move the temp file onto that path (OpenSandbox move_files refuses to overwrite, and a direct upload truncates in place);
  2. write live catalog rows whose names are absent from the snapshot the same way, so a script created during this run is callable through script_run;
  3. remove managed files whose names are in neither set.

script_create and Scripts view writes update PostgreSQL immediately. They write through to a running machine only for names absent from the current run's snapshot. The run-time effects of an edit, a create, and a delete are in Each run keeps its own copy.

Execution ​

A script with parameters = null is reusable code invoked through script_run(name, arguments?). A script with a parameter schema is also offered to the model as a first-class tool under its script name on new runs.

Both paths run the file through guilds-script-run, in the agent's home, with a 120-second timeout. The arguments (the optional arguments object of script_run, or the first-class tool's arguments) are serialised as JSON into GUILDS_SCRIPT_ARGS, on top of the command's usual environment. An arguments string is parsed as JSON. A value that is not a JSON object is refused (arguments must be a JSON object).

The launcher writes that value to the script's stdin, {} when script_run has no arguments. Stdout and stderr pass through the standard tool output pipeline.

The command carries the agent's environment like every other command (Agent home).

Free software under the GNU Affero General Public License, version 3 only.