veryfront serve
runtime instead. That runtime discovers all project agents and tools, then routes
each signed control-plane request by agentId. Projects on a managed dedicated
server do not require a service.ts entrypoint. Add one only when you
intentionally run the standalone Agent Service process described in this guide.
Managed runtimes can execute a connected agent from another project’s immutable
release. The control plane authorizes the connection before dispatch: run.project
identifies the project that owns conversations, runs, tools, and billing, while
sourceProject identifies the project and environment supplying agent definitions.
The signed request audience remains the source runtime’s project. Registration
alone does not authorize another project or relax the runtime’s signature checks.
Source reads use a separate, read-only credentials.sourceAuthToken. The source
project’s environment variables and runtime token are not passed to the connected
execution. Platform tool calls and inference use the consuming run’s credentials.
Child runs must inherit the authorized source connection through the control plane.
Connected execution evaluates project modules in an invocation-specific registry
namespace, including discovery under the consuming project’s credential context.
This prevents reuse of closures containing the source project’s secrets or a
previous invocation’s credentials. Framework registries and evaluated-module cache
entries are retired when the response completes, fails, or is cancelled. Deno’s
ESM module map itself lasts for the process lifetime. The managed shared renderer
pool bounds this retention with memory-triggered, graceful pod recycling. Dedicated
runtime deployments need their own equivalent recycling policy before enabling
repeated connected runs; the shared pool’s policy does not cover those deployments.
Connected agents and their child agent runs are supported. Starting, resuming, or
retrying a source-defined durable workflow from connected execution is rejected
before accessing the workflow backend. Durable workflow recovery needs a separate
persisted source authorization and credential-renewal contract; ordinary same-project
workflows and explicit calls to the consuming project’s existing APIs keep their
existing behavior.
Prerequisites
- At least one agent in
agents/that the service should expose (see Agents). - A deployment target you can run a long-running Node process on.
- For Veryfront Cloud registration:
VERYFRONT_API_TOKEN,VERYFRONT_PROJECT_IDorVERYFRONT_PROJECT_SLUG, and a publicly reachableVERYFRONT_AGENT_SERVICE_URL. See Configuration for the full list. - Immutable deployment metadata for
runtimeSourcewhen the control plane invokes the service.
Create a service entrypoint
Create a process entrypoint that starts the default Veryfront Cloud agent service runtime:startNodeVeryfrontCloudAgentService() starts the runtime from the environment
that is already loaded. It does not load local .env files or initialize
process-wide telemetry. Load standalone service environment files through the
trusted deployment wrapper before it imports service.ts. Project modules
cannot mutate the shared process environment through the public agent API.
Initialize service-level OpenTelemetry in the trusted deployment wrapper before
it loads service.ts. Do not let project code select process-wide exporters,
trace hooks, or application-error reporters. The framework-owned
veryfront serve runtime owns this setup on shared and managed dedicated
servers.
The standalone service shares a process with the Agent code it loads. Use it
for trusted code. Captured request accessors protect specific ingress operations;
they do not provide process isolation for request bodies or credentials.
Custom host route handlers receive the original request and remain responsible
for authentication and credential handling.
Dispatch visits the host route table and matched path segments by index so a
replaced array iterator cannot inject a handler before host authentication.
CORS allowlist membership, response header writes, and route path parsing also
use captured operations.
Sparse route, origin, method, and header arrays ignore inherited
entries. Route handlers retain ordinary-object params; decoded keys bypass
inherited setters.
Framework responses supply explicit status, status text, and empty-header defaults
to native constructors. These defaults override writable inherited data properties,
including CORS headers for a denied origin, and apply only to omitted values.
If Object.prototype defines an accessor for headers, status, or statusText,
response construction throws a TypeError before native option conversion can
invoke it.
On Node, non-writable inherited data properties for these fields also
cause native construction to throw a TypeError. The runtime does not remove
these properties, return an empty response, or
retry with weaker CORS rules. Invalid response values still fail native
validation, and host handler errors propagate unchanged.
The service discovers the same project primitives as the app runtime:
agents/tools/skills/resources/prompts/workflows/tasks/
/api/runs requests. Pass agentId when the service exposes
multiple agents and direct requests need a predictable default.
Hosted tool execution preserves the selected agent ID and durable run ID. Remote
tool calls carry these identities so they match the run authorization claims.
If you customize createTaskContext, return the resolved agentId in that context.
Hosted execution uses that identity, including any normalization your hook applies.
Keep agent behavior in project files
Define the agent inagents/ and keep service startup separate from agent
behavior:
veryfront.config.ts under ai.<primitive>.discovery.paths.
Configure registration
Control-plane registration is convention-first. Inauto mode, the service
registers only when VERYFRONT_API_TOKEN and
VERYFRONT_AGENT_SERVICE_URL are present. Registration also requires the
immutable runtimeSource binding described below.
VERYFRONT_PUBLIC_API_BASE_URL to the environment’s HTTPS API origin.
Run-scoped inference credentials use that public origin for provider gateway
requests and never travel over the internal HTTP connection.
Use VERYFRONT_AGENT_SERVICE_REGISTRATION=enabled when startup must fail if the
service cannot register. Use disabled when the service must run without
control-plane registration.
The service name resolves from VERYFRONT_AGENT_SERVICE_NAME, then the nearest
package.json or deno.json name, then veryfront-agent-service. Pass
serviceName only when code should override that convention.
Bind control-plane runs to the deployed source
A standalone agent service discovers one local project snapshot at startup. It cannot select another project branch or release for an individual request. Bind the service to deployment-owned immutable metadata when it accepts signed control-plane runtime invocations:agentSource
exactly matches runtimeSource. An unbound service returns
CONTROL_PLANE_AGENT_SOURCE_UNBOUND. A different release or environment
returns CONTROL_PLANE_AGENT_SOURCE_MISMATCH. Branch sources are mutable and
return CONTROL_PLANE_AGENT_SOURCE_UNSUPPORTED.
Do not resolve runtimeSource from the latest deployment at request time. Pass
the environment and release identifiers that produced the running service
artifact. Direct /api/runs requests do not select project source and do not
require this binding.
Add remote MCP tools
UsemcpServers when the service needs remote tools. Use
veryfrontApiMcpServer() and veryfrontStudioMcpServer() for
Veryfront-owned control-plane MCP servers and normal MCP server config objects
for third-party servers.
This service startup config uses endpoint and headers. Per-agent config in
agent({ mcpServers }) uses transport, auth, and toolPolicy.
mcpServers is omitted, the Veryfront Cloud preset includes
veryfrontApiMcpServer() by default. Pass mcpServers: [] to run without
remote MCP tools.
Reach trusted deployment-local MCP servers
The default remote MCP source uses guarded outbound networking. Keep that default for third-party, request-derived, and tenant-configured endpoints. A separately deployed agent service may need to reach a trusted MCP server on a private cluster address. In that case, capture the host transport and the exact allowed endpoints once at startup. Use the host transport only for those immutable endpoints and preserve the guarded source for everything else:http: is
appropriate only for private deployment-local networking; use https: for
public networks. Never put a callback endpoint or a per-request URL in the
trusted endpoint list.
Refresh runtime state
UseresolveRuntimeState when a long-lived service run must refresh
instructions, context, or available tools at a model step boundary.
fetchDefaultAgentServiceProjectSteering() for the initial fetch and
createDefaultAgentServiceProjectSteeringRefresh() for step-boundary refresh.
Managed brokers can use createManagedBrokerProjectState() from
veryfront/agent/managed-broker for project instructions and skill catalogs.
The executor sends its effective tool selection on each steering refresh. The
broker validates that selection against the installed grant before constructing
instructions, and includes skills only when load_skill remains available.
Refreshes without a tool selection omit the skill catalog.
Managed broker ingress checks application strings and property names for known
credentials after URI decoding. Malformed escapes do not suppress checks on valid
encoded segments. Decoding is limited to 16 passes; ingress rejects strings that
still require decoding after that limit. Keep credentials out of executor data,
including encoded URLs and metadata.
Closing the managed broker handler or aborting its service signal returns 503
BROKER_UNAVAILABLE for pending admission. Request-only cancellation returns 499
BROKER_INGRESS_ABORTED.
Keep inference authority separate
Signed runtime invocations may include an optionalcredentials.inferenceAuthToken alongside the broader
credentials.authToken. The inference credential is bound to the exact run and
agent and is intended only for attributed Veryfront Cloud model requests. It is
size-bounded to 16 KB, uses visible ASCII token characters, and remains optional
so existing producers and consumers stay compatible.
Treat this as trusted-host authority. Do not copy it into project context,
tools, logs, durable request payloads, or a general API client. Framework-managed
agent services bind it only after the signed invocation and run-event credential
have been verified, bypass project model overrides for Veryfront Cloud models,
and send it only to an HTTPS (or loopback development) gateway. Custom runtime
adapters should follow the same boundary: use authToken for project and
control-plane operations, and expose inferenceAuthToken only to the model
subprocess’s Veryfront Cloud gateway configuration.
Use lower-level helpers
UsestartNodeVeryfrontCloudAgentService() for the standard service shape.
Use lower-level helpers only when the service needs a custom server adapter,
custom execution preparation, or custom infrastructure.
Migrate custom durable child event writers
This migration applies to custom hosted runtimes that call the lower-level durable child helpers. Framework-managedstartNodeVeryfrontCloudAgentService() runtimes create and scope writer
capabilities internally.
Raw authToken, apiUrl, and runEventAppendToken fields no longer grant
durable child event-writer authority. The parsed hosted request also excludes
the writer credential. Keep the credential inside trusted ingress and replace
the removed fields with an opaque HostedRunEventWriterCapability.
Apply the change at every integration point your custom runtime implements:
The generated
veryfront/agent reference
lists the complete properties for these contracts.
-
After trusted ingress verifies an exact root-run append credential, create
the root capability. Do not pass a general user API token.
-
Pass that exact-parent capability to helpers that own child persistence and
capability delegation. Do not pre-mint for these helpers.
-
For lower-level helpers that receive an already-persisted
durableChildRun, mint and pass an exact-child capability: -
Update detached starter callbacks to accept the isolated request:
Managed executor startup
startExecutorRuntimeEntrypoint is available from
veryfront/agent/executor-runtime. It starts the executor side of a managed
broker/executor deployment on Node.js 22 or newer. Your trusted image launcher
calls initializeExecutorRuntimeContracts() from the same export to initialize
the first-party schema validator, bundler, module lexer, and Skill document
parser, then supplies the Operator allocation environment and image
manifest. Missing runtime contracts fail startup.
The executor accepts one authenticated runtime.install message bound to its
allocation, invocation, generation, owner, and immutable source. Discovery remains
unavailable until installation succeeds. The trusted image launcher selects the
profile at startup; channel messages cannot change it.
Installation profiles
The full-runtime profile uses a separate bounded stream for initial checkpoint
state, so durable replay state can exceed the installation message limit.
The project-tools profile is selected by
startExecutorRuntimeEntrypoint({ mode: "project-tools" }). Its installation has
the following shape; the broker supplies the actual allocation and source identities:
allowedToolNames contains unique canonical names, with at most 1024 entries.
maxCalls is an integer from 1 to 4096; maxConcurrent is an integer from 1 to 32.
The fixed context binds tool calls to the admitted canonical run. Correlation IDs,
cancellation and progress use the authenticated channel. This payload accepts no
runtime grants, private credentials or host capability IDs, and rejects unknown
fields. This profile exposes neither runtime preparation nor agent streaming;
the trusted broker owns the agent loop and privileged operations.
The fixed context also accepts optional userId and projectSlug from the approved
execution grant. Project tools receive those captured values; caller conflicts fail.
For canonical execution using a globally owned source, context.projectId may be
explicitly null.
The tool receives no project ID, while its canonical run ID
remains bound. A projectless context must not include a project slug, and a
project-owned source still requires a project ID. Omitting projectId does not
select global execution.
Global steering may be provided as an explicit granted
capability; it is not inferred from a placeholder project. This support does not
enable ephemeral execution or project transitions in the trusted broker.
An explicitly enabled project source can receive the current call’s activeSkillId
and bounded activeSkillToolAvailability.
Omitted skill fields clear prior values.
Credentials and other caller context fields do not cross the project channel.
Unknown startup mode values fail before bootstrap configuration or artifact access.
Selected inline tools and discovered tools are combined under the exact project
source policy, including metadata access and later execution. Framework-generated
agent runtime tools are excluded from the project-only catalog, even when their
names appear in a grant.
The full-runtime profile applies the same source-policy scope while extracting
inline tools and reading their metadata during preparation.
The optional installation limits object contains every field below. Each value
is a positive integer no greater than its default. Omission selects the defaults;
partial overrides are accepted by the trusted broker’s tools.limits option,
which normalizes a complete object for installation.
maxCalls counts source enumeration, listing and execution, including admitted
failures. The trusted broker shares call and concurrency accounting across host
and project tools. Cancellation holds an admitted slot until original work settles.
maxMetadataBytes includes the validated project alias frame plus the combined
host and project source/definition frames. Repeated listings keep consuming the
same invocation budget.
An ordinary project-tool failure releases its shared slot after the failure frame
and normal channel end are confirmed. Cancellation, malformed or incomplete
responses, and unknown transport failures retain that slot until allocation
retirement, even when the caller’s cancellation signal remains live.
Broker composition
The hosted service’sDELETE /api/runs/:runId route requires verified cancellation
authority for that exact run before changing execution state or remembering a
delayed-start cancellation. The default runtime verifies the API’s existing signed
cancellation bearer with its configured public key. Two claim shapes are accepted,
one for each shape the API mints: a project- and run-scoped veryfront-server
service-account bearer carrying tokenUse: project_scoped_service_account, and,
for a run with no project, the requester’s own session bearer, which carries no
tokenUse at all.
Both shapes are pinned by a contract fixture holding payloads
captured from the API’s minting code, so a claim change on either side fails a
test instead of rejecting every cancellation in production. A general user token
without a matching run claim is insufficient, and development decode-only
authentication does not grant cancellation. Custom route sets must supply
verifyRunCancellationToken; omission returns HTTP 403.
The API retains actor and
collaborator authorization before minting the runtime credential. Request-owned
AG-UI streams still support cancellation through their request signal.
The requirement sits at the effect, not only at that route. createAgUiCancelHandler
and createAgUiResumeHandler both require an authorizeRunControl decision, and the
session manager takes verified authority rather than a run id for the cancel-and-tombstone
and resume paths. The run the effect reaches is read out of that authority, so a
surface that mounts either handler cannot reach the registry without a decision, and
authority granted for one run or operation cannot be redirected to another. Run
control the runtime itself performs, such as a session or waiting timeout, still
cancels by run id and cannot create a delayed-start cancellation.
Resume carries the same contract. The default runtime verifies the bearer the API
signs for POST /api/control-plane/runs/:runId/resume against the same public key.
The default route set also serves POST /api/runs/:runId/resume with the same
verification and signal handler.
Both routes refuse an invalid bearer before
changing the waiting run. Resume has no separate mint: the API signs it with the run-bound service credential it already
uses for the stream, so two claim shapes are accepted, both bound to one run and one
project. A run whose record names an actor service account and an agent access grant
carries tokenUse: run_scoped_service_account with that grant recorded in the token;
every other project-bound run carries the veryfront-server service-account bearer
with tokenUse: project_scoped_service_account.
The API refuses to resume a run with
no project before it mints anything, so no projectless resume shape exists. Both
shapes are pinned by a contract fixture holding payloads captured from the API’s
signing path, including the scope ordering, which differs between the two mints. The
grant relation is recorded rather than re-derived, so the API’s collaborator policy
stays the API’s decision.
Custom route sets that serve resume must supply
verifyRunResumeToken; omission returns HTTP 403. Both resume routes enforce the
1 MiB request-body limit on the incoming stream before calling custom authentication.
Authentication receives a separate request with the bounded original body, so it may
read JSON without consuming the signal handler’s input.
Oversized declared or chunked
bodies return HTTP 413 before authentication and cancel the remaining stream.
Standalone resume and cancel handlers apply the same bound before run-id resolvers
and authorizers receive a body. Cancellation without a body remains supported.
Cancellation claims and request bindings must be own data properties. The route
also rejects inherited then properties before authentication and rechecks after
asynchronous verification. This prevents known thenable pollution from replacing
JWT verification results. These checks do not isolate arbitrary project code
running in the service process; use a separate trusted broker process for that
boundary.
The broker owns HTTP authentication, credentials, model and tool authorization,
and durable persistence. Executor facades call these capabilities through the
authenticated channel. Closing a runtime revokes its facades; admission remains
held until the original work and cleanup settle. This entrypoint requires the
broker and isolation infrastructure to be configured separately.
Use veryfront/agent/managed-broker for the broker composition and signed
control-plane HTTP adapter. createManagedDurableBrokerHandler handles direct
POST /api/runs requests with detached execution and requires run-event token
verification and output persistence. createManagedAgUiBrokerHandler handles
direct POST /api/ag-ui requests with request-owned SSE. Its ingress must supply
verifyProjectAccess for requests containing a project ID. Without that verifier,
project requests return HTTP 403 before preparation or allocation; projectless
requests can still proceed.
Configure each direct
adapter’s owner in trusted service configuration; project owners reject requests
for other projects before preparation or allocation. Their prepare callbacks
receive private broker authority and bounded executor data separately. Resolve
immutable sources and capabilities in the broker before returning the executor
start input.
These adapters share admission, duplicate handling, and retirement
with the signed adapter.
The broker installs invocation grants, describes
the selected agent, and prepares the executor before accepting a run. It keeps
model and tool execution unavailable during preparation. Configure detached
202 responses or request-owned SSE responses in trusted service configuration.
Signed, direct durable, and direct AG-UI ingress reject application strings or property
names containing a known broker credential, including credentials embedded in messages
or attachment URLs.
Detached runs require output persistence callbacks; their finalization remains
part of the session’s owned work until all writes settle.
Canonical runs must pass the persistence adapter’s bindSessionOwnedWork
callback in ManagedExecutorStartInput. The broker binds it after reserving a
session and before installation or preparation. Scheduled, retry, and explicit
event-queue writes use that session owner. A persistence timeout can return
promptly while pool capacity stays reserved until the original write settles.
createManagedBrokerPersistenceFromCapability accepts the opaque writer returned
by managed ingress’s createRunEventWriterCapability, the canonical run projection,
and an opaque terminal capability created by createManagedBrokerTerminal.
The writer pins event append to its run, API endpoint and transport. The terminal
factory takes independent completion credentials, the run projection, model and
provider resolution, and trusted API transport. It keeps the run binding and
completion operation in private state. Relabeled, cloned, fabricated, and
other-run terminal handles are rejected before writes.
An event-writer token cannot authenticate the API’s /complete route. The terminal
factory uses that route with independent application authority; it does not accept
arbitrary completion callbacks or implement the detached-completion protocol.
The raw-token createManagedBrokerPersistence constructor requires both
runEventToken and a distinct completionAuthToken accepted by the API completion
route. Existing callers must add that completion credential; the constructor
rejects omission or reuse of the append token. Provider resolution is called without
exposing private adapter options as its receiver. Both constructors require the
same session binding and cleanup. Tokens and terminal capabilities remain in the broker.
startNodeManagedAgentBroker binds the signed stream, durable start, AG-UI,
and cancel/resume handlers to a Node server. Supply every handler, the broker
pool, and a readiness check explicitly. It preserves /liveness and
/readiness; shutdown stops admission before waiting for handlers and broker
work to retire. This server adapter does not configure product policy,
registration, credentials, or executor images.
Managed run routes return HTTP 400 with BROKER_INGRESS_TARGET_MISMATCH when
a run ID contains malformed URL encoding or fails the canonical run ID schema
after decoding. Run IDs contain 1 to 128 ASCII letters, digits, underscores,
or hyphens. Valid encoded run IDs are decoded before the handler receives them.
Signed stream requests must sign the original encoded request path.
To verify the packaged broker and executor locally, use Node.js 22.3.0 or newer:
Verify it worked
Start the service entrypoint and call the run route directly. The default port is3001; override with PORT if needed.
VERYFRONT_AGENT_SERVICE_HEARTBEAT_INTERVAL_MS).
Broker model output limits and provider-tool descriptors must stay within the installed model grant.
Each broker tool capability must also stay within the installed tool allowlist. Startup rejects broader
broker authority before allocating an executor.
Preparation uses the narrower broker model output
limits and provider-tool list, so its default model requests fit the broker policy. Anthropic thinking
with an additive token budget reserves that budget from the total allowance before preparation chooses
the completion limit. Adaptive thinking uses the total allowance without an additive reservation.
Preparation rejects an explicit completion limit that exceeds the remainder. Source IDs must
belong to the installed host-facade or remote-source grants. Owner-scoped tool selectors use the same
canonical names for capability checks and steering refreshes.
Trusted ingress must provide tools.catalog with the complete tool inventory and ownership metadata,
including project-local tools that have no broker capability. The broker resolves short selectors to
owned tools first, then validates source capabilities against those exact IDs. Preparation and steering
refreshes receive the same resolved grant.
A shadowed global tool does not gain authority from an owned
tool’s short selector. The catalog must come from trusted source metadata before executor discovery.
For selected host tools, the broker includes the catalog’s owner and short-name mapping in the
validated installation.
Rebuilt executor facades retain that mapping, so an agent’s short selector
continues to select the same canonical tool. Remote source listings do not supply ownership authority.