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).
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# User Folder Layout
|
||||
|
||||
## Overview
|
||||
|
||||
Every authenticated user gets a personal folder at `data/users/{userId}/`.
|
||||
This folder is the user's private, cross-task workspace. Unlike a job's
|
||||
ephemeral workspace (which lives under `{worktree_dir}/local/{taskId}/` and is
|
||||
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`.
|
||||
- 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.
|
||||
|
||||
Access is **owner-only**: the REST API enforces that only the owner (or an
|
||||
admin) can read, write, or delete files inside the folder. The directory is
|
||||
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' })`.
|
||||
|
||||
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`
|
||||
parameter is set. Each recording lands here as `{name}.json` once the session
|
||||
ends. The file contains an ordered list of timestamped actions.
|
||||
|
||||
You never write here directly — the server writes recordings automatically.
|
||||
The **User Folder → recordings/** panel lets you view recordings and convert them
|
||||
to browser macros via **Save as Script** (saves to `browser-macros/`).
|
||||
|
||||
### `browser-sessions/`
|
||||
|
||||
**Virtual subdir (no actual filesystem directory).** Manages saved browser login
|
||||
profiles — cookies and storage state captured via noVNC (CAPTCHA/2FA bypass).
|
||||
Sessions are encrypted with a per-user key.
|
||||
|
||||
Managed from the **User Folder → browser-sessions/** panel in the UI:
|
||||
1. Click "Add site session", enter the URL and a label.
|
||||
2. Log in inside the noVNC window that opens.
|
||||
3. Click Save — the encrypted storage state is written to the DB.
|
||||
|
||||
Browser macros reference a session by `session_profile_id: <N>` in their frontmatter.
|
||||
|
||||
### `trash/`
|
||||
|
||||
Soft-deleted scripts, macros, templates, and recordings are moved here rather than
|
||||
immediately erased. Files in `trash/` accumulate with a timestamp prefix:
|
||||
`{YYYYMMDD-HHMMSS}-{rand4hex}-{name}`. Restore by copying the content back to the
|
||||
original subdir via the editor.
|
||||
|
||||
### `memory/`
|
||||
|
||||
Persistent memory entries managed by the `UpdateUserMemory` and `ReadUserMemory` tools.
|
||||
|
||||
**`MEMORY.md`** (index file) — automatically injected into the agent's system prompt at the start of every movement. It contains one line per entry:
|
||||
|
||||
```
|
||||
- [preferred-language](preferred-language.md) — User prefers Japanese output
|
||||
- [project-stack](project-stack.md) — Tech stack for the main project
|
||||
```
|
||||
|
||||
**Individual fact files** (`{name}.md`) — each has YAML frontmatter followed by a plain Markdown body:
|
||||
|
||||
```
|
||||
---
|
||||
name: preferred-language
|
||||
description: User prefers Japanese output
|
||||
type: user
|
||||
---
|
||||
Always respond in Japanese unless the user explicitly asks for another language.
|
||||
```
|
||||
|
||||
**Note:** `MEMORY.md` is agent-managed via `UpdateUserMemory`. Manual edits to the index file are tolerated but may cause duplicate lines if you change the link format `- [name](file.md)`.
|
||||
|
||||
**Memory types:**
|
||||
|
||||
| Type | Intended use |
|
||||
|------|-------------|
|
||||
| `user` | Long-term user preferences, standing instructions |
|
||||
| `feedback` | Corrections the user has given (e.g. "don't do X") |
|
||||
| `project` | Project-specific facts (stack, conventions, key files) |
|
||||
| `reference` | Reference data (URLs, credentials patterns, external IDs) |
|
||||
|
||||
---
|
||||
|
||||
## AGENTS.md
|
||||
|
||||
`data/users/{userId}/AGENTS.md` (at the top level of your user folder, not
|
||||
inside a subdirectory) is your **personal agent instruction file**. Whenever
|
||||
the orchestrator starts a task on your behalf it reads this file and injects
|
||||
its contents into the agent's system prompt, before any piece-specific
|
||||
instructions.
|
||||
|
||||
Edit it from the **Settings → Agent instructions** panel or with any text
|
||||
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 macros (`browser-macros/`)
|
||||
|
||||
```js
|
||||
---
|
||||
description: "Log in and navigate to the dashboard"
|
||||
params:
|
||||
- name: username
|
||||
type: string
|
||||
- name: password
|
||||
type: string
|
||||
session_profile_id: 1
|
||||
---
|
||||
async function main({ context, params }) {
|
||||
const page = await context.newPage();
|
||||
try {
|
||||
await page.goto('https://example.com/login');
|
||||
await page.locator('#username').fill(params.username);
|
||||
await page.locator('#password').fill(params.password);
|
||||
await page.locator('button[type=submit]').click();
|
||||
} finally {
|
||||
await page.close();
|
||||
}
|
||||
}
|
||||
module.exports = main;
|
||||
```
|
||||
|
||||
Invocation: `RunUserScript({ name: 'login', kind: 'browser-macro', params: { username: '...', password: '...' } })`
|
||||
|
||||
Full field reference, parameter passing, and session-profile selection are documented in [docs/tools/runuserscript.md](tools/runuserscript.md).
|
||||
|
||||
---
|
||||
|
||||
## Self-Healing Script Patches
|
||||
|
||||
When a `RunUserScript` call with `kind: 'browser-macro'` fails because a selector no longer matches the page, the agent automatically enables the BrowseWeb recorder. The recorded interactions are compiled into a candidate patch at `browser-macros/{name}.next.js`.
|
||||
|
||||
The Diff review pane in **User Folder → browser-macros/** compares the current `.js` with the `.next.js` candidate and asks you to approve or reject the patch. On approval the server atomically replaces `{name}.js`. On rejection the staging file is discarded.
|
||||
|
||||
This means the live `browser-macros/` folder always contains only reviewed, approved code.
|
||||
|
||||
---
|
||||
|
||||
## Permissions and Privacy
|
||||
|
||||
The `data/users/{userId}/` directory is created with mode `0700` (owner read/write/execute only) at the filesystem level. At the API level every endpoint under `/api/users/me/` requires a valid session cookie and verifies that the authenticated user's ID matches the folder being accessed. Admin users can access any user's folder.
|
||||
|
||||
No other user — including users in the same organisation — can list or read your scripts, macros, templates, recordings, or AGENTS.md.
|
||||
|
||||
### Auth-disabled mode (local dev only)
|
||||
|
||||
When the `auth:` section is absent from `config.yaml` (`authActive=false`), the User Folder API injects a synthetic `{ id: 'local', role: 'user' }` user, so all operations go to `data/users/local/`. Production deployments should always run with auth enabled.
|
||||
Reference in New Issue
Block a user