DocsTools and agent

Tools and agent

Everything an agent’s code can call. This reference comes from Tilda’s plugin itself: the documents its kernel serves to agents through agent.documentation, and the type declarations its skills ship in repl.d.ts. It’s shown as agents read it, so parts of it speak to the agent.

The tools#

Agents get two tools. JsReplExec runs one cell of JavaScript:

InputTypeAs the tool describes it
codestringRaw JavaScript source to run. Do not send JSON, a quoted string, or a markdown fence. Static imports and await import() are supported under the kernel import rules.
titlestringShort plain-language label shown to the user. Describe the browser or work step. For example "Open the sign-in page" or "Read the order total".
timeout_ms (optional)numberPositive cell timeout in milliseconds. Default 120000. A timeout abandons the cell but does not cancel its work.

JsReplReset takes no inputs. It clears every binding and closes every page, tab group, and terminal that agent opened.

The documents agents read#

In a cell, agent.documentation.get(name) returns one of these documents, and agent.documentation.catalog() lists them. Each configured MCP server adds one more, mcp:<server>, describing its tools.

DocumentWhat it coversOn this site
browserStart a browser session and choose the next reference document.Your browser
browser-apiSupported Browser, BrowserContext, Page, and assertion methods and signatures.Browser API
locatorsCreate, narrow, read, and act on locators.Browser API
networkWait for responses and route requests.Browser API
eventsListen for page events and wait for page state.Browser API
downloadsWait for downloads and work with downloaded files.Browser API
files-and-dialogsUpload files, handle file choosers, dialogs, and the clipboard.Browser API
cdpUse page-level or browser-level Chrome DevTools Protocol sessions.Browser API
codemodeKernel state, inputs, timeout rules, imports, output, reset, and images.The kernel
terminalRun commands with child_process; run a dev server, REPL, or prompt under agent.terminals.Terminals
computer-apiControl macOS apps with agent.computer's Playwright-shaped windows and locators.Mac apps
troubleshootingRecover from browser, page, locator, frame, key, and dialog errors.Troubleshooting
securityApproval rules, untrusted content, browser permissions, and data access.Security and permissions
mcpCall the MCP servers in ~/.tilda/mcp.json from a cell with agent.mcp; configure, discover, trust rules.MCP servers
subagentsStart other coding agents as subagents with agent.subagents, each in a preset's role; talk to them and approve.Subagents

By area#

Standard Node.js globals and modules work in every cell as well, and aren’t listed here.

Types#

As declared in the repl.d.ts the skills ship. Constructors are left out: code in a cell is handed these objects and doesn’t build them.

Agent#

/** Available in every REPL cell via the `agent` global. */
interface Agent {
	/** The connected browser registry: list(), get(id), getDefault(). */
	browsers: Browsers;
	/** Playwright-shaped macOS application control. */
	computer: Computer;
	/** Runtime documentation the agent reads with get(name) / list() / catalog(). */
	documentation: Documentation;
	/**
	 * The MCP servers in ~/.tilda/mcp.json: list(), reload(), and one handle
	 * per server, `agent.mcp.<server>.<tool>(args)`. Read
	 * `agent.documentation.get("mcp:<server>")` for a server's tools.
	 */
	mcp: Mcp & {
		[server: string]: McpServer;
	};
	/**
	 * Other coding agents as subagents of this session, each in a preset's role:
	 * presets(), spawn(), message(), decide(), interrupt(), list(),
	 * transcript(). Read `agent.documentation.get("subagents")` first.
	 */
	subagents: Subagents;
	/**
	 * Programs under a real terminal, kept by tmux so they outlive this process:
	 * open(name, command), get(name), list(), killAll(). Run a plain command with
	 * node:child_process instead.
	 */
	terminals: Terminals;
	/** Current working directory of the server process. */
	cwd: string;
	/** User home directory. */
	homeDir: string;
	/** Temporary directory. The bare global tmpDir is the same value. */
	tmpDir: string;
	/**
	 * Send a picture into the current cell result. Accepts bytes, a data URL,
	 * base64, { bytes, mimeType }, { image_url }, or a tool result with image
	 * content.
	 */
	viewImage(imageLike: unknown, options?: {
		mimeType?: string;
	}): Promise<{
		bytes: number;
	}>;
}

global#

declare global {
	/** Available in every REPL cell: browsers, documentation, paths, viewImage. */
	const agent: Agent;
	/** Playwright-shaped assertions: expect(page.getByRole("button")).toBeVisible(). */
	const expect: Expect;
	/** Temporary directory of the server process. */
	const tmpDir: string;
	/** Dynamic import through codemode's resolver (builtins, .js/.mjs files, bare packages). */
	function __import(specifier: string): Promise<unknown>;
}

Documentation#

class Documentation {
	get(name: string): Promise<string>;
	list(): Promise<string[]>;
	catalog(): Promise<Array<{
		name: string;
		description: string;
	}>>;
}

DocumentName#

type DocumentName = "browser" | "browser-api" | "locators" | "network" | "events" | "downloads" | "files-and-dialogs" | "cdp" | "codemode" | "computer-api" | "troubleshooting" | "security" | "mcp" | "subagents";

Subagents#

class Subagents {
	/** Every preset, with the models this machine can run for it and why the others cannot run. */
	presets(): Promise<SubagentPresetInfo[]>;
	/**
	 * Starts a subagent on `task` and returns at once; it works in the background.
	 * It runs on a random one of the preset's models this machine can run, or on
	 * `model` when given. `access` defaults to "auto": the subagent's own reviewer
	 * model decides, and what it will not allow comes to you as an approval request.
	 */
	spawn(input: {
		preset: SubagentPreset;
		task: string;
		cwd: string;
		model?: string;
		access?: SubagentAccess;
	}): Promise<SubagentInfo>;
	/**
	 * Sends `text` to the subagent: it answers an open question, joins the running
	 * turn, or starts the next one once the subagent is idle.
	 */
	message(input: {
		id: string;
		text: string;
	}): Promise<SubagentInfo>;
	/** Settles one of the subagent's approval requests. */
	decide(input: {
		id: string;
		requestId: string;
		decision: "allow" | "deny";
	}): Promise<SubagentInfo>;
	/** Ends the running turn; the subagent stays and takes the next message. An idle one is left as it is. */
	interrupt(input: {
		id: string;
	}): Promise<SubagentInfo>;
	/** This session's subagents, oldest first. */
	list(): Promise<SubagentInfo[]>;
	/** What the subagent did, in brief, from entry `sinceSeq` on. */
	transcript(input: {
		id: string;
		sinceSeq: number;
		limit: number;
	}): Promise<SubagentTranscript>;
}

SubagentPresetInfo#

type SubagentPresetInfo = {
	preset: SubagentPreset;
	purpose: string;
	choices: {
		model: string;
		effort: "high" | "low" | "max" | "medium" | "xhigh" | null;
	}[];
	unavailable: {
		model: string;
		effort: "high" | "low" | "max" | "medium" | "xhigh" | null;
		reason: string;
	}[];
};

SubagentPreset#

type SubagentPreset = "explore" | "implement" | "reason" | "review";

SubagentAccess#

type SubagentAccess = "auto" | "full" | "read-only";

SubagentInfo#

type SubagentInfo = { model: string; effort: "high" | "low" | "max" | "medium" | "xhigh" | null; id: string; preset: "explore" | "implement" | "reason" | "review"; access: "auto" | "full" | "read-only"; cwd: string; pending: ({ kind: "approval"; requestId: string; action: "tool" | "command" | "file-change" | "permissions"; summary: string; blocking: boolean; } | { kind: "question"; requestId: string; questions: { id: string; question: string; options: string[]; }[]; })[]; } & { status: "running"; } | { model: string; effort: "high" | "low" | "max" | "medium" | "xhigh" | null; id: string; preset: "explore" | "implement" | "reason" | "review"; access: "auto" | "full" | "read-only"; cwd: string; pending: ({ kind: "approval"; requestId: string; action: "tool" | "command" | "file-change" | "permissions"; summary: string; blocking: boolean; } | { kind: "question"; requestId: string; questions: { id: string; question: string; options: string[]; }[]; })[]; } & { status: "done"; text: string; } | { model: string; effort: "high" | "low" | "max" | "medium" | "xhigh" | null; id: string; preset: "explore" | "implement" | "reason" | "review"; access: "auto" | "full" | "read-only"; cwd: string; pending: ({ kind: "approval"; requestId: string; action: "tool" | "command" | "file-change" | "permissions"; summary: string; blocking: boolean; } | { kind: "question"; requestId: string; questions: { id: string; question: string; options: string[]; }[]; })[]; } & { status: "failed"; reason: string; } | { model: string; effort: "high" | "low" | "max" | "medium" | "xhigh" | null; id: string; preset: "explore" | "implement" | "reason" | "review"; access: "auto" | "full" | "read-only"; cwd: string; pending: ({ kind: "approval"; requestId: string; action: "tool" | "command" | "file-change" | "permissions"; summary: string; blocking: boolean; } | { kind: "question"; requestId: string; questions: { id: string; question: string; options: string[]; }[]; })[]; } & { status: "interrupted"; };

SubagentTranscript#

type SubagentTranscript = {
	entries: {
		seq: number;
		at: number;
		role: "tool" | "parent" | "subagent" | "tilda";
		text: string;
	}[];
	nextSeq: number;
};

WebSocket#

/**
 * Playwright-shaped WebSocket (thin).
 * @see https://playwright.dev/docs/api/class-websocket
 */
class WebSocket {
	url(): string;
	isClosed(): boolean;
}

FileChooser#

/**
 * Playwright-shaped file chooser (from waitForEvent("filechooser")).
 * @see https://playwright.dev/docs/api/class-filechooser
 */
class FileChooser {
	page(): Page;
	isMultiple(): boolean;
	setFiles(files: string | string[]): Promise<void>;
}

Dialog#

/**
 * Playwright-shaped JavaScript dialog (alert / confirm / prompt / beforeunload).
 * @see https://playwright.dev/docs/api/class-dialog
 */
class Dialog {
	type(): "alert" | "beforeunload" | "confirm" | "prompt" | string;
	message(): string;
	defaultValue(): string;
	page(): Page;
	accept(promptText?: string): Promise<void>;
	dismiss(): Promise<void>;
}

SubagentRequest#

type SubagentRequest = {
	kind: "approval";
	requestId: string;
	action: "tool" | "command" | "file-change" | "permissions";
	summary: string;
	blocking: false | true;
} | {
	kind: "question";
	requestId: string;
	questions: {
		id: string;
		question: string;
		options: string[];
	}[];
};

SubagentOutcome#

type SubagentOutcome = {
	status: "done";
	text: string;
} | {
	status: "failed";
	reason: string;
} | {
	status: "interrupted";
};

SubagentEvent#

type SubagentEvent = { seq: number; subagent: string; } & { kind: "message"; text: string; } | { seq: number; subagent: string; } & { kind: "request"; request: { kind: "approval"; requestId: string; action: "tool" | "command" | "file-change" | "permissions"; summary: string; blocking: boolean; } | { kind: "question"; requestId: string; questions: { id: string; question: string; options: string[]; }[]; }; } | { seq: number; subagent: string; } & { kind: "finished"; outcome: { status: "done"; text: string; } | { status: "failed"; reason: string; } | { status: "interrupted"; }; };

expect#

const expect: Expect;