This commit is contained in:
@@ -1,85 +0,0 @@
|
||||
# ReadUserTemplate
|
||||
|
||||
Loads a template file from the caller's `templates/` subdir (`data/users/{userId}/templates/`).
|
||||
|
||||
## Overview
|
||||
|
||||
Templates are plain Markdown files the user stores in their `templates/` folder via the UI.
|
||||
Unlike `memory/` entries, frontmatter is **optional** — a template can be pure Markdown prose
|
||||
with no YAML header at all.
|
||||
|
||||
Use this tool when the user says "use the weekly-report template" or "follow the api-error-email
|
||||
boilerplate" — call `ReadUserTemplate`, read the shape, then adapt it to the task at hand.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```json
|
||||
{ "name": "weekly-report" }
|
||||
```
|
||||
|
||||
Or with the `.md` extension (both forms work):
|
||||
|
||||
```json
|
||||
{ "name": "weekly-report.md" }
|
||||
```
|
||||
|
||||
**Response example (no frontmatter):**
|
||||
|
||||
```
|
||||
# Template: weekly-report
|
||||
|
||||
## Body
|
||||
# Weekly Report
|
||||
|
||||
Fill in this week's highlights here.
|
||||
```
|
||||
|
||||
**Response example (with frontmatter):**
|
||||
|
||||
```
|
||||
# Template: api-error-email
|
||||
|
||||
## Frontmatter
|
||||
title: "API Error Email"
|
||||
audience: "external"
|
||||
|
||||
## Body
|
||||
Dear customer,
|
||||
|
||||
We apologize for the inconvenience.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | string | Yes | Template filename, with or without `.md` extension (max 128 chars) |
|
||||
|
||||
---
|
||||
|
||||
## Error cases
|
||||
|
||||
- Returns an error if the template does not exist in `templates/`.
|
||||
- Returns an error if no user is authenticated.
|
||||
- Returns an error if `name` contains path traversal characters or slashes.
|
||||
|
||||
---
|
||||
|
||||
## Use cases
|
||||
|
||||
- Weekly / monthly report boilerplate: `ReadUserTemplate({ name: "weekly-report" })` → fill in stats.
|
||||
- Email canned responses: `ReadUserTemplate({ name: "api-error-email" })` → personalise and send.
|
||||
- Code boilerplate: `ReadUserTemplate({ name: "react-component" })` → generate a new component.
|
||||
|
||||
---
|
||||
|
||||
## Related tools
|
||||
|
||||
- `ListUserAssets({ kind: "templates" })` — see what templates exist before reading one.
|
||||
- `ReadUserMemory` — for structured facts/preferences (requires frontmatter).
|
||||
- `RunUserScript` — for executable Node/Playwright scripts stored in `scripts/` / `browser-macros/`.
|
||||
- This tool is a META_TOOL — no need to add it to `allowed_tools` in piece YAML.
|
||||
@@ -1,108 +0,0 @@
|
||||
# RenderUserTemplate
|
||||
|
||||
Renders a template from `templates/` by substituting `{{var}}` placeholders with caller-supplied params.
|
||||
|
||||
## Overview
|
||||
|
||||
Companion to `ReadUserTemplate`. Instead of returning the raw body, this tool:
|
||||
|
||||
1. Parses the template's frontmatter `params` spec (same shape as scripts / browser-macros).
|
||||
2. Validates caller-supplied `params` against the spec (type-check + defaults applied).
|
||||
3. Replaces every `{{name}}` placeholder in the body with the resolved value.
|
||||
4. Returns the rendered body (no `# Template:` header, no frontmatter — just the substituted text).
|
||||
|
||||
Placeholders **not declared** in `frontmatter.params` are left literal — so prose like
|
||||
`use {{column}} as the key` survives unchanged when no `column` param exists.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Template file `templates/weekly-report.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: Weekly status report
|
||||
params:
|
||||
- name: date
|
||||
type: string
|
||||
- name: summary
|
||||
type: string
|
||||
default: "(no summary)"
|
||||
---
|
||||
# Status — {{date}}
|
||||
|
||||
{{summary}}
|
||||
```
|
||||
|
||||
Call:
|
||||
|
||||
```json
|
||||
{ "name": "weekly-report", "params": { "date": "2026-05-11", "summary": "shipped 3 PRs" } }
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
# Status — 2026-05-11
|
||||
|
||||
shipped 3 PRs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | string | Yes | Template filename, with or without `.md` extension (max 128 chars) |
|
||||
| `params` | object | No | Key-value params matching the template's `frontmatter.params` spec |
|
||||
|
||||
---
|
||||
|
||||
## Frontmatter `params` schema
|
||||
|
||||
Identical to scripts / browser-macros:
|
||||
|
||||
```yaml
|
||||
params:
|
||||
- name: identifier # must match /^[a-zA-Z_$][a-zA-Z0-9_$]*$/
|
||||
type: string | number | boolean
|
||||
description: optional
|
||||
default: optional # if omitted, the param is required
|
||||
```
|
||||
|
||||
Param values are coerced to string via `String(value)` when substituted.
|
||||
|
||||
---
|
||||
|
||||
## Error cases
|
||||
|
||||
- `name` missing or invalid characters → error.
|
||||
- Template file does not exist in `templates/` → error.
|
||||
- Frontmatter is malformed (bad YAML, bad `params` shape) → error.
|
||||
- A required param (no default) is missing from the call → error: `param X: required but not provided`.
|
||||
- A param has the wrong type → error: `param X: expected number, got string`.
|
||||
|
||||
Templates without any frontmatter render as pure pass-through — any `{{var}}` stays literal.
|
||||
|
||||
---
|
||||
|
||||
## Use cases
|
||||
|
||||
- Weekly / monthly reports: `RenderUserTemplate({ name: "weekly-report", params: { date, summary } })`.
|
||||
- Email canned responses with variable substitution.
|
||||
- Code boilerplate with a few configurable parts (component name, props).
|
||||
|
||||
For more dynamic logic (conditionals, loops), open `ReadUserTemplate` and do the substitution
|
||||
inline in your output — there is no Handlebars / Liquid / etc. engine, by design.
|
||||
|
||||
---
|
||||
|
||||
## Related tools
|
||||
|
||||
- `ReadUserTemplate` — returns the raw body + frontmatter. Use this when you want to inspect
|
||||
the template structure or do substitution yourself.
|
||||
- `ListUserAssets({ kind: "templates" })` — list available templates.
|
||||
- `RunUserScript` — for executable scripts (not just text substitution).
|
||||
- This tool is a META_TOOL — no need to add it to `allowed_tools` in piece YAML.
|
||||
+34
-52
@@ -1,27 +1,29 @@
|
||||
# RunUserScript
|
||||
|
||||
Executes a user-authored script from the caller's user folder.
|
||||
Executes a user-authored Playwright browser-macro from the caller's
|
||||
`browser-macros/` folder.
|
||||
|
||||
Two kinds of scripts are supported:
|
||||
> **Retired (2026-06):** plain-Node `scripts/` (the old `kind: 'script'`) and
|
||||
> `templates/` were removed. Keep reusable procedures/boilerplate in **Skills**,
|
||||
> and run ad-hoc code (Node, Python, …) with the **Bash** tool. Passing
|
||||
> `kind: 'script'` now returns an error pointing at those replacements.
|
||||
|
||||
| kind | directory | runtime | signature | use case |
|
||||
|------|-----------|---------|-----------|----------|
|
||||
| `'script'` (default) | `scripts/` | plain Node.js — no Chromium | `main({ params })` | Data processing, API calls, computation, file conversion |
|
||||
| `'browser-macro'` | `browser-macros/` | Playwright — Chromium | `main({ context, params })` | Web automation with a live browser session |
|
||||
| directory | runtime | signature | use case |
|
||||
|-----------|---------|-----------|----------|
|
||||
| `browser-macros/` | Playwright — Chromium | `main({ context, params })` | Web automation with a live browser session |
|
||||
|
||||
## Input
|
||||
|
||||
```ts
|
||||
{
|
||||
name: string, // filename — '.js' is appended if absent
|
||||
params?: Record<string, unknown>, // runtime values matching the script's param spec
|
||||
kind?: 'script' | 'browser-macro' // default: 'script'
|
||||
params?: Record<string, unknown>, // runtime values matching the macro's param spec
|
||||
}
|
||||
```
|
||||
|
||||
## Param validation
|
||||
|
||||
Params are validated against the `params:` block in the script's YAML frontmatter:
|
||||
Params are validated against the `params:` block in the macro's YAML frontmatter:
|
||||
- Extra params not listed in the spec → error containing "param"
|
||||
- Wrong type for a declared param → error containing "param"
|
||||
- Missing required param (no default) → error containing "param"
|
||||
@@ -29,9 +31,9 @@ Params are validated against the `params:` block in the script's YAML frontmatte
|
||||
|
||||
On any param error the tool returns `isError: true` immediately — no subprocess is spawned.
|
||||
|
||||
## Session integration (browser-macro only)
|
||||
## Session integration
|
||||
|
||||
If a `browser-macro` script's frontmatter declares `session_profile_id: <N>`, the tool:
|
||||
If the macro's frontmatter declares `session_profile_id: <N>`, the tool:
|
||||
|
||||
1. Loads the profile from the DB (owner-gated — must belong to `ctx.userId`).
|
||||
2. Decrypts the user's envelope-encrypted DEK using the master key.
|
||||
@@ -40,13 +42,12 @@ If a `browser-macro` script's frontmatter declares `session_profile_id: <N>`, th
|
||||
|
||||
If any step fails the tool returns `isError: true` with a descriptive message.
|
||||
|
||||
For `kind: 'script'` (plain runtime), `session_profile_id` in the frontmatter is ignored — no session is loaded.
|
||||
## Self-healing recorder
|
||||
|
||||
## Self-healing recorder (browser-macro only)
|
||||
|
||||
When a `browser-macro` fails at runtime, the tool automatically enables the BrowseWeb recorder for the current task (if not already enabled). On task completion, `recording-flush` stages a candidate patch as `browser-macros/{name}.next.js` for diff review.
|
||||
|
||||
Plain scripts (`kind: 'script'`) do **not** auto-enable the recorder.
|
||||
When a macro fails at runtime, the tool automatically enables the BrowseWeb
|
||||
recorder for the current task (if not already enabled). On task completion,
|
||||
`recording-flush` stages a candidate patch as `browser-macros/{name}.next.js`
|
||||
for diff review.
|
||||
|
||||
## Output format
|
||||
|
||||
@@ -58,14 +59,9 @@ On success:
|
||||
<console.log lines from the child process>
|
||||
```
|
||||
|
||||
The result is JSON-stringified if it is an object or array; `String(result)` otherwise. The `[script logs]` section is only appended when the script produced logs.
|
||||
The result is JSON-stringified if it is an object or array; `String(result)` otherwise. The `[script logs]` section is only appended when the macro produced logs.
|
||||
|
||||
On failure (plain):
|
||||
```
|
||||
RunUserScript "{name}" failed: <error message>
|
||||
```
|
||||
|
||||
On failure (browser-macro):
|
||||
On failure:
|
||||
```
|
||||
RunUserScript "{name}" failed: <error message>
|
||||
|
||||
@@ -78,36 +74,22 @@ On task complete, a candidate patch will be saved as browser-macros/{name}.next.
|
||||
| Situation | `isError` | message contains |
|
||||
|-----------|-----------|-----------------|
|
||||
| No authenticated user | true | "authenticated" |
|
||||
| Script file not found | true | "not found" |
|
||||
| Macro file not found | true | "not found" |
|
||||
| Retired `kind: 'script'` passed | true | "retired" |
|
||||
| Frontmatter parse error | true | "frontmatter" |
|
||||
| Param type / missing error | true | "param" |
|
||||
| Session profile not found / not owned | true | "not found or does not belong" |
|
||||
| Profile not active | true | "not active" |
|
||||
| DEK / blob decryption failure | true | "decrypt" |
|
||||
| Script timeout (60 s) | true | "timeout" |
|
||||
| Script exits non-zero | true | "exited code" |
|
||||
| Plain script denied child_process (e.g. spawning python) | true | "exited code" + "use the Bash tool" |
|
||||
| Macro timeout (60 s) | true | "timeout" |
|
||||
| Macro exits non-zero | true | "exited code" |
|
||||
|
||||
## Notes
|
||||
|
||||
- The tool is a META_TOOL — it is available in every movement without listing it in `allowed_tools`.
|
||||
- Use `kind: 'browser-macro'` for any script that needs a browser (`context`).
|
||||
- Use `ListUserAssets` first to discover available scripts and their param specs.
|
||||
- On browser-macro failure, use `BrowseWeb` as a manual fallback.
|
||||
|
||||
## Running Python (don't — use Bash)
|
||||
|
||||
`RunUserScript` runs **Node only**. There is no Python interpreter path. A
|
||||
common footgun is to write a Node script that does
|
||||
`child_process.spawn('python3', ...)` and run it here — that **cannot work**:
|
||||
plain scripts run under Node's `--permission` model, which denies
|
||||
`child_process` entirely (you get `ERR_ACCESS_DENIED`). Even if it were
|
||||
allowed, the child's env is scrubbed, so it would not see the orchestrator's
|
||||
provisioned Python environment.
|
||||
|
||||
To run Python, use the **`Bash` tool** instead: `python3 your_script.py`. The
|
||||
Bash sandbox has the pip packages pre-baked (pypdf, pdfplumber, python-docx,
|
||||
python-pptx, openpyxl, pandas, numpy, …). That is the supported, working path.
|
||||
- Use `ListUserAssets` first to discover available macros and their param specs.
|
||||
- On macro failure, use `BrowseWeb` as a manual fallback.
|
||||
- To run Python or other ad-hoc code, use the **Bash** tool (pip packages pre-baked).
|
||||
|
||||
## Security and trust model
|
||||
|
||||
@@ -118,13 +100,13 @@ tools:
|
||||
user_scripts_enabled: true
|
||||
```
|
||||
|
||||
**Only enable for trusted users.** User scripts run in a restricted child process:
|
||||
- Env is scrubbed — only `PATH`, `HOME`, `TMPDIR/TMP`, `LANG`, `NODE_ENV`, and `PLAYWRIGHT_BROWSERS_PATH` are forwarded. API keys, database passwords, and other secrets in the orchestrator's environment are not visible to the script.
|
||||
**Only enable for trusted users.** Macros run in a restricted child process:
|
||||
- Env is scrubbed — only `PATH`, `HOME`, `TMPDIR/TMP`, `LANG`, `NODE_ENV`, and `PLAYWRIGHT_BROWSERS_PATH` are forwarded. API keys, database passwords, and other secrets in the orchestrator's environment are not visible to the macro.
|
||||
- CWD is set to the system tmpdir, not the orchestrator workspace.
|
||||
- Stdout is capped at 1 MB and stderr at 200 KB; exceeding either limit kills the child.
|
||||
- On timeout, the entire process group (including Playwright's Chromium for browser-macros) is killed.
|
||||
- On timeout, the entire process group (including Playwright's Chromium) is killed.
|
||||
|
||||
**The two runtimes have different capability levels:**
|
||||
|
||||
- **Plain scripts (`kind: 'script'`)** run under Node's Permissions Model (`--permission`): `--allow-fs-read` is limited to the child-runner dir and tmpdir, `--allow-fs-write` to tmpdir, and `child_process`, worker threads, and native addons are **denied**. A plain script that tries to spawn a subprocess (e.g. python) fails with `ERR_ACCESS_DENIED`. See "Running Python" above.
|
||||
- **Browser-macros (`kind: 'browser-macro'`)** cannot use `--permission` — Chromium launch, native bindings, and outbound HTTPS all need unrestricted `child_process`/addons/network. They run with full Node.js capability (env-scrubbed only) and rely on container-level isolation. Treat them as trusted code.
|
||||
Browser-macros cannot use Node's `--permission` model — Chromium launch, native
|
||||
bindings, and outbound HTTPS all need unrestricted `child_process`/addons/network.
|
||||
They run with full Node.js capability (env-scrubbed only) and rely on
|
||||
container-level isolation. Treat them as trusted code.
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
# WriteUserScript
|
||||
|
||||
Creates or overwrites a script in the caller's user folder.
|
||||
Creates or overwrites a Playwright browser-macro in the caller's
|
||||
`browser-macros/` folder.
|
||||
|
||||
Two destinations are supported:
|
||||
> **Retired (2026-06):** plain-Node `scripts/` (the old `kind: 'script'`) and
|
||||
> `templates/` were removed. Keep reusable procedures/boilerplate in **Skills**,
|
||||
> and run ad-hoc code with the **Bash** tool. Passing `kind: 'script'` now
|
||||
> returns an error pointing at those replacements.
|
||||
|
||||
| kind | directory | runtime | signature |
|
||||
|------|-----------|---------|-----------|
|
||||
| `'script'` (default) | `scripts/` | plain Node.js | `main({ params })` |
|
||||
| `'browser-macro'` | `browser-macros/` | Playwright — Chromium | `main({ context, params })` |
|
||||
| directory | runtime | signature |
|
||||
|-----------|---------|-----------|
|
||||
| `browser-macros/` | Playwright — Chromium | `main({ context, params })` |
|
||||
|
||||
## Input
|
||||
|
||||
@@ -15,7 +18,6 @@ Two destinations are supported:
|
||||
{
|
||||
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
|
||||
}
|
||||
```
|
||||
@@ -26,14 +28,14 @@ The content must define a `main` function. The following forms are all accepted:
|
||||
|
||||
```js
|
||||
// ES function declaration
|
||||
async function main({ params }) { … }
|
||||
async function main({ context, params }) { … }
|
||||
|
||||
// Arrow / assigned function
|
||||
const main = async ({ params }) => { … };
|
||||
const main = async ({ context, params }) => { … };
|
||||
|
||||
// CommonJS export
|
||||
module.exports = async function main({ params }) { … };
|
||||
exports.main = async function({ params }) { … };
|
||||
module.exports = async function main({ context, params }) { … };
|
||||
exports.main = async function({ context, params }) { … };
|
||||
```
|
||||
|
||||
If none of these patterns is found the tool returns `isError: true` with a
|
||||
@@ -53,10 +55,10 @@ params:
|
||||
---
|
||||
```
|
||||
|
||||
Frontmatter is parsed by `RunUserScript` for param validation. Scripts without
|
||||
Frontmatter is parsed by `RunUserScript` for param validation. Macros without
|
||||
frontmatter still run, but param validation is skipped.
|
||||
|
||||
Browser macros may additionally declare `session_profile_id: <N>` to auto-load
|
||||
Macros may additionally declare `session_profile_id: <N>` to auto-load
|
||||
a saved login session (see `RunUserScript` docs).
|
||||
|
||||
## Size limit
|
||||
@@ -70,41 +72,15 @@ 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 discovered a useful browser-automation pattern during a task — save it for next time.
|
||||
- The user asks you to create or update a macro they can run later via `RunUserScript`.
|
||||
- You want to prototype a browser automation without going through the UI.
|
||||
|
||||
## Examples
|
||||
|
||||
### Plain Node script
|
||||
|
||||
```js
|
||||
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
|
||||
## Example
|
||||
|
||||
```js
|
||||
WriteUserScript({
|
||||
name: "screenshot-dashboard",
|
||||
kind: "browser-macro",
|
||||
content: `---
|
||||
description: Take a screenshot of the dashboard
|
||||
params:
|
||||
@@ -126,6 +102,7 @@ async function main({ context, params }) {
|
||||
| Situation | `isError` | message contains |
|
||||
|-----------|-----------|-----------------|
|
||||
| No authenticated user | true | "authenticated" |
|
||||
| Retired `kind: 'script'` passed | true | "retired" |
|
||||
| `name` missing / empty | true | `"name"` |
|
||||
| `name` contains `/`, space, etc. | true | "alphanumeric" |
|
||||
| `content` missing `main` | true | "main" |
|
||||
@@ -135,5 +112,5 @@ async function main({ context, params }) {
|
||||
## 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.
|
||||
- After writing, use `RunUserScript` to immediately execute and verify the macro.
|
||||
- Use `ListUserAssets` to see all macros currently in the folder.
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
# WriteUserTemplate
|
||||
|
||||
Creates or overwrites a Markdown template in the caller's `templates/` folder.
|
||||
|
||||
Templates written here are immediately usable by `ReadUserTemplate` (to inspect them) and `RenderUserTemplate` (to substitute `{{var}}` placeholders and apply defaults).
|
||||
|
||||
## Input
|
||||
|
||||
```ts
|
||||
{
|
||||
name: string, // slug — '.md' appended if absent
|
||||
content: string, // full file text (optional frontmatter + Markdown body)
|
||||
overwrite?: boolean // default: false — error if file exists
|
||||
}
|
||||
```
|
||||
|
||||
## File structure
|
||||
|
||||
The content is plain Markdown with an optional YAML frontmatter block:
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: One-line description shown in ListUserAssets
|
||||
params:
|
||||
- name: date
|
||||
type: string
|
||||
- name: author
|
||||
type: string
|
||||
default: "Team"
|
||||
---
|
||||
# Report — {{date}}
|
||||
|
||||
Prepared by: {{author}}
|
||||
|
||||
## Highlights
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
Frontmatter is not required. Templates without `params:` render as-is (no substitution).
|
||||
|
||||
## Frontmatter params spec
|
||||
|
||||
Each param entry in `params:` supports:
|
||||
|
||||
| field | required | description |
|
||||
|-------|----------|-------------|
|
||||
| `name` | yes | placeholder name used as `{{name}}` in the body |
|
||||
| `type` | yes | `string` \| `number` \| `boolean` |
|
||||
| `default` | no | value applied when the param is omitted |
|
||||
|
||||
Required params (no default) must be supplied by the caller of `RenderUserTemplate`. Missing required params produce an error at render time.
|
||||
|
||||
## Size limit
|
||||
|
||||
128 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 file atomically.
|
||||
|
||||
## When to use
|
||||
|
||||
- You noticed a recurring structure (email skeleton, weekly report, issue template) — persist it for reuse.
|
||||
- The user asks you to create or update a template so they can render it later.
|
||||
- You want to encode a multi-step prompt skeleton with named slots.
|
||||
|
||||
## Examples
|
||||
|
||||
### Email template
|
||||
|
||||
```js
|
||||
WriteUserTemplate({
|
||||
name: "api-error-email",
|
||||
content: `---
|
||||
description: Customer-facing API error notification email
|
||||
params:
|
||||
- name: incident_id
|
||||
type: string
|
||||
- name: service
|
||||
type: string
|
||||
- name: eta
|
||||
type: string
|
||||
default: "unknown"
|
||||
---
|
||||
Dear Customer,
|
||||
|
||||
We have detected an issue with **{{service}}** (incident {{incident_id}}).
|
||||
|
||||
Our team is actively working on a resolution. Estimated resolution time: **{{eta}}**.
|
||||
|
||||
We apologize for the inconvenience.
|
||||
|
||||
— The Platform Team
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### Report skeleton (no params)
|
||||
|
||||
```js
|
||||
WriteUserTemplate({
|
||||
name: "weekly-retro",
|
||||
content: `# Weekly Retro
|
||||
|
||||
## What went well
|
||||
-
|
||||
|
||||
## What to improve
|
||||
-
|
||||
|
||||
## Action items
|
||||
- [ ]
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
## Error cases
|
||||
|
||||
| Situation | `isError` | message contains |
|
||||
|-----------|-----------|-----------------|
|
||||
| No authenticated user | true | "authenticated" |
|
||||
| `name` missing / empty | true | `"name"` |
|
||||
| `name` contains `/`, space, etc. | true | "alphanumeric" |
|
||||
| Content exceeds 128 KB | true | "bytes" |
|
||||
| File exists, `overwrite` not set | true | "overwrite" |
|
||||
|
||||
## Notes
|
||||
|
||||
- `WriteUserTemplate` is a META_TOOL — available in every movement without listing it in `allowed_tools`.
|
||||
- After writing, use `ReadUserTemplate` to verify the content and `RenderUserTemplate` to test substitution.
|
||||
- Use `ListUserAssets` to see all templates currently in the folder.
|
||||
@@ -9,7 +9,7 @@ tied to a single run), the user folder **persists indefinitely** across tasks,
|
||||
sessions, and server restarts.
|
||||
|
||||
The primary use-cases are:
|
||||
- Storing reusable scripts (`scripts/`) and browser macros (`browser-macros/`) that any of your tasks can invoke via `RunUserScript`.
|
||||
- Storing reusable browser macros (`browser-macros/`) that any of your tasks can invoke via `RunUserScript`.
|
||||
- Keeping template files and reference documents you want agents to access without uploading them every time.
|
||||
- Holding auto-generated recordings of browser sessions so you can review or convert them later.
|
||||
- Managing saved browser login sessions (`browser-sessions/`) that macros can use.
|
||||
@@ -22,32 +22,21 @@ created on first login and is never shared between accounts.
|
||||
|
||||
## Subdirectories
|
||||
|
||||
### `scripts/`
|
||||
|
||||
**AI-generated plain Node.js programs.** No Chromium. Signature: `main({ params })`.
|
||||
|
||||
Best for: data processing, API calls, computation, file conversion, scheduled task helpers — anything that does not need a browser.
|
||||
|
||||
Files are edited directly in the **User Folder → scripts/** panel. The agent writes and runs these via `RunUserScript({ name, kind: 'script' })` (the default `kind`).
|
||||
|
||||
See [docs/tools/runuserscript.md](tools/runuserscript.md) for the exact file format and invocation details.
|
||||
|
||||
### `browser-macros/`
|
||||
|
||||
**Playwright-based browser automation scripts.** Launches Chromium. Signature: `main({ context, params })`.
|
||||
|
||||
Generated automatically by the **Save as Script** button in the recordings panel (previously these went to `scripts/`). Can also be written manually in the UI. The agent runs them via `RunUserScript({ name, kind: 'browser-macro' })`.
|
||||
> **Retired (2026-06):** the former `scripts/` (plain Node) and `templates/`
|
||||
> subdirectories were removed. Reusable procedures/boilerplate belong in
|
||||
> **Skills**; ad-hoc code runs via the agent's **Bash** tool. Existing files
|
||||
> remain on disk but are no longer listed or runnable.
|
||||
|
||||
Generated automatically by the **Save as Script** button in the recordings panel. Can also be written manually in the UI. The agent runs them via `RunUserScript({ name })`.
|
||||
|
||||
If a `session_profile_id` is declared in the frontmatter, the corresponding saved browser session (from `browser-sessions/`) is loaded automatically.
|
||||
|
||||
**Self-healing patches**: when a macro fails, the agent auto-enables the BrowseWeb recorder; on task completion a candidate patch is staged as `browser-macros/{name}.next.js`. The Diff review pane lets you accept or reject it. See [Self-Healing Patches](#self-healing-script-patches) below.
|
||||
|
||||
### `templates/`
|
||||
|
||||
Static files — Markdown snippets, HTML skeletons, CSV headers, prompt
|
||||
fragments — that you want to reuse across tasks. Agents can read these with
|
||||
the standard `Read` tool by referencing the path the API returns.
|
||||
|
||||
### `recordings/`
|
||||
|
||||
Browser-session recordings produced by `BrowseWeb` when the `record_to`
|
||||
@@ -126,25 +115,7 @@ editor — the agent picks up the latest version at the start of each task.
|
||||
|
||||
---
|
||||
|
||||
## Script vs Browser-Macro Format
|
||||
|
||||
### Plain scripts (`scripts/`)
|
||||
|
||||
```js
|
||||
---
|
||||
description: "Fetch and summarise data"
|
||||
params:
|
||||
- name: url
|
||||
type: string
|
||||
---
|
||||
async function main({ params }) {
|
||||
const data = await fetch(params.url).then(r => r.json());
|
||||
return data.summary;
|
||||
}
|
||||
module.exports = main;
|
||||
```
|
||||
|
||||
Invocation: `RunUserScript({ name: 'my-script', kind: 'script', params: { url: '...' } })`
|
||||
## Browser-Macro Format
|
||||
|
||||
### Browser macros (`browser-macros/`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user