Skip to main content
An agent is a file in agents/ that exports a system prompt, optional tools, optional memory, and optional skills. The runtime auto-discovers it on startup and exposes it via getAgent(id) or a route created with createAgUiHandler(). For the normal path, omit model and let runtime conventions choose: local inference by default, Veryfront Cloud when VERYFRONT_API_TOKEN plus project context are set.

Prerequisites

  • A Veryfront project running locally (see Create project).
  • A provider configured for inference (see Providers).
  • The agents/ directory exists. If you customised ai.agents.discovery.paths in Configuration, use that directory instead.

Define an agent

Create a file in agents/:
The id is how you reference the agent later with getAgent("assistant"). You can also define an agent with markdown when the agent only needs persona, model, and step configuration:
The file path provides the agent id. For example, agents/support.md registers support and can be invoked through the same project runtime and control-plane surfaces as agents/support.ts.

Per-agent skills and tools

A markdown agent can own its skills and tools by using a directory instead of a single file. Put the agent definition in AGENT.md and colocate its capabilities beside it:
The directory name is the agent id. The flat agents/{id}.md form still works for agents that do not own skills or tools, and both layouts can coexist. Colocated capabilities are registered with owner metadata and namespaced {agentId}--{name}. Ownership controls visibility everywhere: an agent only ever sees unowned (project-global) capabilities plus its own - never another agent’s. This one rule applies to skills: and tools: for every agent kind (TypeScript, flat markdown, and directory markdown):
  • Omit skills or use skills: true to advertise and authorize every skill visible to the agent. Use skills: [] to advertise none and to authorize no project or configured skill for load_skill.
  • tools: true - every currently scoped tool is authorized, while non-bootstrap schemas are deferred behind tool_search until the agent searches for them.
  • skills: [..] / tools: [..] - each entry resolves as the agent’s own short name first, then as a global id. A colocated short name that shadows a global id is reported at discovery so the reference stays unambiguous.
  • Duplicate agent ids (flat file + directory) and agent ids whose sanitized namespaces collide are reported as discovery errors. The same catalog metadata is used by local and hosted runtime paths. Hosted skill loading uses the catalog sourcePath, not a path reconstructed from the namespaced id, so load_skill("researcher--cite") resolves to the actual colocated SKILL.md.

Add tools

Agents call tools to take actions or fetch data. Reference tools by name: the framework resolves them from the tools/ directory:
temperature controls model sampling and defaults to 0. It does not guarantee repeatable output. Runtime provider capabilities may omit or normalize the value for models that reject generic sampling parameters or require mode-specific values. maxSteps limits how many tool-call iterations the agent can perform per request. See Tools for how to define getWeather.

Load broad tool catalogs progressively

The tools selector controls both authorization and initial schema exposure:
  • Omit tools to expose no project tools.
  • Use an explicit map to expose only those selected schemas immediately.
  • Use tools: true to authorize every tool in the current scope while initially exposing only bootstrap tools and tool_search.
A successful search makes matching authorized schemas visible on the next model step.
The framework tool_search fallback is provider-neutral. It searches the authorized tools catalog and configured providerTools that the selected model supports. Provider-native entries contain only a name and description until a search loads them. The runtime attaches the provider’s native schema on the next model step. Search ranks an exact tool name first, followed by normalized substrings in the tool name, description, and input parameter descriptions. It returns at most five names and descriptions. Results never include schemas, and tool_search has no pagination options. Loading a schema never authorizes a tool. The runtime rechecks authorization before execution. It also filters restored loaded-tool state against the currently authorized catalog. You can use deferred loading with a direct provider and its API key without Veryfront Cloud. Hosted durable runs additionally require the Veryfront API durable run-event contract. The hosted runtime stores loaded-tool state in a private checkpoint and waits for that checkpoint before continuing. Private checkpoint data does not appear in public messages or replay. Configured, supported provider-native tools use the same private exposure checkpoint. Provider replay is not part of this feature. See Tools for the search and execution flow.

Enable provider tools

Provider tools are executed by the selected model provider. They are not local tools and they are not MCP tools.
The runtime only enables provider tools that the selected provider/model supports.

Connect MCP servers

Use mcpServers for remote MCP-compatible tool servers. Put visibility policy on the server that owns the tools. When tools is an explicit object, include the remote MCP tool name in tools and authorize it with the server toolPolicy. Explicitly named tools that are not local are resolved from the Veryfront API MCP server when mcpServers is omitted and the server bootstrap is available. This lets a project pulled from Studio run locally without repeating transport configuration. VERYFRONT_API_URL selects the API endpoint; VERYFRONT_API_TOKEN and VERYFRONT_PROJECT_SLUG provide server-side identity. These environment variables do not grant tools by themselves.
Only the explicitly named unresolved tools are requested from the remote MCP catalog. Remote tools/list remains authoritative, and browser AG-UI context cannot replace server identity. Set mcpServers: [] to opt out. An explicit mcpServers list overrides the default; use { kind: "veryfront-api" } with a toolPolicy when the connection policy should travel with the agent.

Use skills

Skills are reusable instruction packs discovered from your project’s skills/ directory. Every agent receives the visible skill catalog and load_skill automatically.
Use skills: ["incident-response", "repo-maintainer"] to advertise and authorize only those skills. Use skills: [] to advertise no skills and to authorize none for load_skill. An explicit selector is an authorization boundary for load_skill, not just a prompt filter. Local and project runtimes also expose load_skill_reference and execute_skill_script. Hosted chat reads an advertised reference through load_skill({ skillId, file }) and does not execute skill scripts directly. See Project structure for skills/ conventions and Configuration for discovery paths.

Skill execution flow

When an agent uses a skill, the flow is:
  1. Call load_skill({ skillId }) to load the skill instructions and policy.
  2. Read an advertised reference with load_skill_reference(...) on local and project runtimes, or load_skill({ skillId, file }) in hosted chat.
  3. On local and project runtimes, optionally call execute_skill_script(...) to run scripts from scripts/.
  4. Continue with normal tool calls. Loading a skill does not change which tools the run may call.
A step may batch load_skill with other tool calls. The runtime runs the calls in the order the model emitted them. A successful load_skill changes only which skill’s instructions are loaded and which reference and script files load_skill_reference and execute_skill_script can reach for later calls. Ordinary tools are unaffected, whether they were emitted before or after load_skill, and a failed load_skill does not block the rest of the batch.

Skill script execution

Skill scripts run in one of two modes, selected automatically:
  • Local (development): When no Veryfront Cloud sandbox credentials are available, scripts run as direct subprocesses on your machine via runCommand(). No remote sandbox is needed.
  • Cloud (production): When SANDBOX_AUTH_TOKEN, VERYFRONT_API_TOKEN, or request-scoped Veryfront credentials are available, scripts are uploaded to and executed inside a remote sandbox session.
Local development does not require sandbox infrastructure. Scripts run as direct subprocesses.

Skill safety model

  • allowed-tools in SKILL.md is not enforced. The Agent Skills specification defines it as pre-approval metadata (tools an agent may run without prompting), not an authorization boundary, so Veryfront records the declaration and does not restrict the run. Narrow a run by configuring the agent’s tools, not by declaring allowed-tools in a skill.
  • Skill file reads are restricted to the skill root and allowed subdirectories: references/, resources/, assets/, and scripts/.
  • Symlinked paths are rejected for skill file access.
  • Script execution timeout defaults to 60000 ms and is capped at 300000 ms.

Connect to a route

Expose a registered agent through createAgUiHandler() when a browser or external client needs AG-UI streaming. Use Create agent for the copyable quick-start route. Use Chat UI to pair that route with useChat(). If a route returns Agent not found, ensure the agent file is in agents/ and its id matches the value passed to createAgUiHandler().

Non-streaming response

For server-side generation (e.g., in getServerData), use generate(). getAgent() returns Agent | undefined, so narrow the result before calling it. Without the guard, the sample fails typecheck under the "strict": true tsconfig that veryfront init writes.

Runtime UTC context

Veryfront captures UTC once at the start of every generate(), stream(), and respond() run. The runtime adds the same server-authored system block before each model step:
Use these values for time-sensitive instructions. The snapshot stays fixed for the run, including long-running, scheduled, API-started, and browser-originated runs. Browser environment context can add a display timezone, but it does not replace the UTC snapshot. Non-streaming results expose the exact values at result.metadata?.runtimeContext; streaming runs emit them in the initial data event named veryfront.runtime_context for durable replay and diagnostics.

Dynamic system prompts

The system property accepts a string, a function, or an async function:
For step-boundary refresh during a long-lived run, use resolveRuntimeState instead of relying on system() to run again mid-turn.

Agent configuration

Verify it worked

Save the agent file, restart veryfront dev, and invoke it from server code:
If generation fails, check the dev-server log for agent registration or provider errors. If AG-UI routing fails, use the route verification in Create agent. A healthy AG-UI stream ends with a RunFinished event.