vlt / affordances
  • Quickstart
  • Concepts
  • Guides
  • Reference
  • For agents
  • Why Affordances
  • Quickstart
  • Benchmarks

Concepts
  • Overview
  • Actions
  • State
  • Expose
  • Guards and confirm
  • Deltas
  • Plugins

Guides
  • Overview
  • React and WebMCP
  • MCP
  • Lint
  • Security

Plugins
  • Overview

Reference
  • Overview
  • Protocol
  • Options
  • CLI
  • defineAction
  • defineState
  • createAffordances
  • createHandler
  • withAffordances
  • CLI
  1. Reference
  2. /
  3. Options

Options

Every option of defineAction, defineState, createAffordances, createHandler, and withAffordances, in one place. The generated API reference has the full signatures.

defineAction

TypeScript
import { defineAction } from '@affordances/next'

Returns a server action that also carries the action's metadata. Use the one from createAffordances({ auth }) to share a session resolver.

OptionTypeDescription
namestringRequired. Unique on the route and stable across releases. Must be a string literal.
descriptionstringRequired. What the action does, written for an agent.
inputStandardSchemaV1Required. Validated on every call. Its JSON Schema becomes the descriptor's input.
run(input, ctx) => OutputRequired. Does the work. May be async, may throw AffordancesError or redirect().
expose'public' | 'session' | 'confirm'Who may call it as an agent. Omitted: agents can't reach it.
stateStateDefThe route's state, so guard, summary, and effects are typed against it.
requiresstringThe precondition in words, shown as the descriptor's guard.
guard({ input, state, ctx }) => boolean | stringtrue to allow, a string with the reason to refuse. input is undefined when building the graph.
summary({ input, state }) => stringWhat a confirm action will do, shown to the person before they approve.
message({ input, output }) => stringA sentence for the delta's message.
effectsstring[]Entity keys the action changes. The delta's changed holds exactly these.
readOnlybooleanMarks the action as side-effect free, for agents and WebMCP's readOnlyHint.
outputStandardSchemaV1Describes the return value as the descriptor's output.
jsonSchemaRecord<string, unknown>The input's JSON Schema, for schema libraries without Standard JSON Schema.

defineState

TypeScript
defineState(loader, { nav })
OptionTypeDescription
loader({ params, searchParams, ctx }) => EntitiesRequired. Returns the page's entities. May be async.
nav(state) => { to: string; label?: string; when?: string }[]Links an agent can follow from this page.

createAffordances

TypeScript
import { createAffordances } from '@affordances/next'

export const { defineAction, defineState } = createAffordances<Session>({ auth })
OptionTypeDescription
auth(request: Request) => Session | nullResolves the caller's session. Used by the route handler and by the UI path. May be async.

createHandler

TypeScript
import { createHandler } from '@affordances/core'
import { createRouteHandler } from '@affordances/next/route'

createHandler is the framework-agnostic handler: (request: Request) => Promise<Response>. createRouteHandler(options) wraps it for Next. It sets basePath: '/api/affordances/graph' and redirectFrom for Next's redirect(), and manifest defaults to the app's generated one. GET and POST from @affordances/next/route are createRouteHandler() with no options.

OptionTypeDescription
manifestManifestRequired. Route patterns mapped to their state and actions. @affordances/next generates it.
basePathstringStripped from the request path before matching, such as /api/affordances/graph.
auth(request: Request) => Session | nullDefaults to the auth the actions were defined with.
rateLimit({ request, action, session }) => true | numbertrue allows the call; a number of seconds answers rate_limited with Retry-After. May be async.
allowedOriginsstring[]Origins besides the request's own that may make cookie-authenticated calls.
redirectFrom(error: unknown) => string | undefinedReads the path from a framework's own redirect error.

withAffordances

TypeScript
import { withAffordances } from '@affordances/next/config'
import { md } from '@affordances/md/next'

export default withAffordances(nextConfig, { name: 'Store', plugins: [md()] })

Returns the same config, with Affordances' rewrites put first in beforeFiles and a Link header on every page that has a graph, then each plugin applied in order. Your own rewrites and headers are kept.

OptionTypeDescription
namestringThe site's name in /.well-known/affordances.json.
rootstringThe project root to scan for app/ or src/app/. Defaults to the directory Next runs in.
plugins((config) => config)[]More Affordances capabilities, applied in order after the graph, e.g. [md()] from @affordances/md/next. Each owns a route under /api/affordances/<name>.

CLI

The affordances commands are in @affordances/cli.


PreviousProtocolNextCLI

On this page

  • defineAction
  • defineState
  • createAffordances
  • createHandler
  • withAffordances
  • CLI
Edit this page

Make your app agent-operable

Give every page a graph and every server action an agent path: HTTP, WebMCP, and MCP, with the same session and the same checks. One command sets it up.

Read the quickstart