maestro/docs/tools/writeuserscript.md
clade 7049a874f3 feat: initial public release (MAESTRO v0.1.0)
Open-source release of MAESTRO, an agent orchestration platform that runs
LLM-driven tasks through sandboxed tools, with a web UI. Apache-2.0.
See README.md and docs/ (getting-started, configuration, architecture).
2026-06-03 04:01:14 +00:00

3.6 KiB

WriteUserScript

Creates or overwrites a script in the caller's user folder.

Two destinations are supported:

kind directory runtime signature
'script' (default) scripts/ plain Node.js main({ params })
'browser-macro' browser-macros/ Playwright — Chromium main({ context, params })

Input

{
  name: string,                        // slug — '.js' appended if absent
  content: string,                     // full file text (frontmatter + main())
  kind?: 'script' | 'browser-macro',  // default: 'script'
  overwrite?: boolean                  // default: false — error if file exists
}

Required file structure

The content must define a main function. The following forms are all accepted:

// ES function declaration
async function main({ params }) {  }

// Arrow / assigned function
const main = async ({ params }) => {  };

// CommonJS export
module.exports = async function main({ params }) {  };
exports.main = async function({ params }) {  };

If none of these patterns is found the tool returns isError: true with a hint to add a main definition.

---
description: One-line human-readable description shown in ListUserAssets
params:
  - name: url
    type: string
  - name: limit
    type: number
    default: 10
---

Frontmatter is parsed by RunUserScript for param validation. Scripts without frontmatter still run, but param validation is skipped.

Browser macros may additionally declare session_profile_id: <N> to auto-load a saved login session (see RunUserScript docs).

Size limit

256 KB (UTF-8 encoded). Exceeding the limit returns isError: true.

Overwrite semantics

By default (overwrite: false) writing to an existing file is an error. Pass overwrite: true to replace the existing file atomically.

When to use

  • You discovered a useful reusable pattern during a task — save it for next time.
  • The user asks you to create or update a script they can run later via RunUserScript.
  • You want to prototype a browser automation without going through the UI.

Examples

Plain Node script

WriteUserScript({
  name: "fetch-and-clean",
  kind: "script",
  content: `---
description: Fetch a URL and return cleaned JSON
params:
  - name: url
    type: string
---
const https = require('https');

async function main({ params }) {
  const res = await fetch(params.url);
  const json = await res.json();
  return { items: json.items ?? [] };
}
`
})

Browser macro

WriteUserScript({
  name: "screenshot-dashboard",
  kind: "browser-macro",
  content: `---
description: Take a screenshot of the dashboard
params:
  - name: url
    type: string
---
async function main({ context, params }) {
  const page = await context.newPage();
  await page.goto(params.url);
  const buf = await page.screenshot({ fullPage: true });
  return { screenshotBase64: buf.toString('base64') };
}
`
})

Error cases

Situation isError message contains
No authenticated user true "authenticated"
name missing / empty true "name"
name contains /, space, etc. true "alphanumeric"
content missing main true "main"
Content exceeds 256 KB true "bytes"
File exists, overwrite not set true "overwrite"

Notes

  • WriteUserScript is a META_TOOL — available in every movement without listing it in allowed_tools.
  • After writing, use RunUserScript to immediately execute and verify the script.
  • Use ListUserAssets to see all scripts currently in the folder.