Skip to main content
Extensions

Custom Host Functions

Expose trusted host functions to agentOS coding agents as typed CLI commands, with scoped input, output, and execution behavior.

Expose your host JavaScript functions (defined with Zod input schemas) to agents as auto-generated CLI commands installed at /bin/agentos-{name} inside the VM, injected into the agent’s system prompt and callable inside scripts for code-mode token savings.

Getting started

Pass agentOS({ hostFunctions }) a record of collections. The keys name everything: the collection key becomes the CLI binary agentos-{name} and a guest global, and each function key becomes a subcommand. A function needs only an inputSchema and an execute handler. .describe() on the schema is what the agent reads.

Each host function can override its timeout in milliseconds. The default is 30 seconds and can be changed with limits.hostFunctions.defaultTimeoutMs.

Zod to CLI mapping

Zod schema fields are converted to CLI flags automatically. Field names are converted from camelCase to kebab-case.

Zod typeCLI syntaxExample
z.string()--name value--path /tmp/out.png
z.number()--name 42--limit 5
z.boolean()--flag / --no-flag--full-page
z.enum(["a","b"])--name a--format json
z.array(z.string())--name a --name b--tags foo --tags bar

Optional fields (via .optional()) become optional flags. Required fields are enforced at validation time. Use .describe() on Zod fields to generate useful --help output, and .describe() on the whole schema to describe the function itself.

What the agent sees

When host functions are registered, CLI shims are installed at /bin/agentos-{name} inside the VM and the function list is injected into the agent’s system prompt, so keep each schema’s .describe() concise to save tokens.

The agent interacts with host functions as shell commands:

# List all available host-function collections
agentos list-host-functions

# List the host functions in a specific collection
agentos list-host-functions weather

# Get help for a host function
agentos-weather forecast --help

# Call a host function with flags
agentos-weather forecast --city Paris --days 3

# Call a host function with inline JSON
agentos-weather forecast --json '{"city":"Paris","days":3}'

# Call a host function with JSON from a file
agentos-weather forecast --json-file /tmp/input.json

On success, the host function exits 0 and writes a JSON envelope to stdout:

{"ok":true,"result":{"temperature":22,"condition":"sunny"}}

On failure (validation or execution error), the host function exits non-zero and writes the error message to stderr:

Missing required flag: --city

Call host functions from JavaScript

Inline JavaScript and TypeScript get each collection as a frozen global, and each host function as an async function, so generated code calls your tools like any other API. Keys written in camelCase become kebab-case commands and camelCase guest identifiers, so orderStore.listOrders is agentos-order-store list-orders on the CLI and orderStore.listOrders(input) in guest JavaScript.

// Each collection is a global inside the VM, and each host function is an
// async function, so generated code calls your tools like any other API.
const llmGeneratedExpression = `(async () => {
  const [sf, tokyo] = await Promise.all([
    tools.weather({ city: "San Francisco" }),
    tools.weather({ city: "Tokyo" }),
  ]);
  return {
    sanFrancisco: sf,
    tokyo,
    differenceF: Math.abs(sf.tempF - tokyo.tempF),
  };
})()`;

The function resolves to the host function’s result and rejects on a schema violation, a thrown error, or a timeout. A collection whose name is already a global, such as process, is not defined, and a warning is written to stderr. The hostFunction permission scope applies exactly as it does to the commands.

Host functions and MCP servers

agentOS supports two ways to give agents access to external functionality: host functions and session-scoped MCP servers. Both work, but they have different tradeoffs.

Host functionsMCP servers
How it worksCall JavaScript functions on the host directlyConnect to a standard MCP server
AuthenticationNone required. Calls go directly to the host process.Requires custom auth configuration per server
Code modeBuilt in. Host functions are exposed as CLI commands, so agents can call them inside scripts for up to 80% token reduction.Requires extra work to make code mode work out of the box
LatencyNear-zero. Bound directly to the host process.Extra network hop to reach the MCP server
SetupDefine host functions in your actor code with Zod schemasConfigure any standard MCP server

Use host functions when you want to expose your own JavaScript functions to agents. Use MCP servers when you want to connect to existing third-party services. See Sessions for MCP server configuration.

Security

Host-function calls from the agent invoke your execute() functions on the host. Your functions run with full access to the host environment, so you can call databases, APIs, and services directly without proxying credentials into the VM. The agent never sees the credentials, only the function’s input/output contract.

Host functions run on the host with full access to the host environment, so do not expose functions that could compromise the host without appropriate safeguards.

Embedded API

Pass the same host-function collections to AgentOs.create(). The function contract and generated VM commands are unchanged.

import { AgentOs } from "@rivet-dev/agentos-core";
import { z } from "zod";

// Host functions are defined exactly as they are for the actor. Pass them to
// AgentOs.create() and `execute` runs in this host process, with its input typed
// by its own schema.
const vm = await AgentOs.create({
	hostFunctions: {
		weather: {
			forecast: {
				inputSchema: z
					.object({ city: z.string().describe("City name") })
					.describe("Get the weather forecast for a city"),
				execute: async ({ city }) => ({ city, temperature: 22 }),
			},
		},
	},
});

// The agent calls it as `agentos-weather forecast --city Paris`.
const result = await vm.process.exec("agentos-weather forecast --city Paris");
console.log(result.stdout);
await vm.dispose();

Read more in the embedded API quickstart.