API Reference
This page documents the public SDK surface exported by @ageniti/core.
Top-Level Import
For most applications, start with the root export:
import {
createAgenitiApp,
createRuntime,
defineAction,
s,
} from "@ageniti/core";Use subpath exports only when you want a narrower import boundary. See Entry Points.
Since 0.2.0: build/package/publish, docs, project, lint, and manifest helpers documented below are imported from dedicated subpaths, not the root entry. Each section below shows the exact subpath. The
app.build(),app.package(),app.publish(),app.createGuideDoc(),app.exportDocs()methods on the result ofcreateAgenitiApp()are unchanged.
defineAction(config)
Defines a typed action contract.
Required fields:
name: lowercase snake_case action namedescription: human-readable action descriptionrun(input, context): action implementation
Optional fields:
versiontitleinputoutputvisibilitysideEffectsidempotencypermissionssupportedSurfacestimeoutMsretryconcurrencyrequiresConfirmationmetadatapublicMetadatadocsdeprecateddeprecation
Metadata model:
metadata: internal action metadata for app code and build-time tooling; it is not copied into public manifests or tool metadatapublicMetadata: safe-to-expose metadata copied into public manifests, MCP tool metadata, and LLM tool adapters
Docs model:
docs: natural-language guidance used to generate a unifiedGUIDE.md- app-level
docssupportssummary,audience,whenToUse,quickStart,setup,operationalNotes,sections, andexamples - action-level
docssupportswhenToUse,whenNotToUse,usageNotes,inputExample, andoutputExample GUIDE.mdis deterministic output; it does not call a model or infer behaviour from UI code
Versioning model:
version: action contract version, default1.0.0deprecated: marks an action as deprecated without removing itdeprecation: optional message, replacement, and timeline metadata
Important defaults:
title: derived fromnameinput:s.object({})visibility:"public"sideEffects:"read"idempotency:"unspecified"permissions:[]supportedSurfaces:cli,json,http,mcp,react,dev,ai-sdkretry: normalised to{ retries, delayMs }requiresConfirmation:truefor destructive actions unless overridden
Example:
const deleteTask = defineAction({
name: "delete_task",
description: "Delete a task by id.",
sideEffects: "destructive",
requiresConfirmation: true,
input: s.object({
taskId: s.string().min(1),
}),
async run(input, ctx) {
return ctx.services.tasks.remove(input.taskId);
},
});createAgenitiApp(options)
Creates an app object that owns actions, runtime, and surface helpers.
const app = createAgenitiApp({
name: "task-app",
description: "Workspace task operations for external tools, automation, and agent callers.",
attribution: {
text: "Powered by Ageniti",
vendor: "Ageniti",
product: "Ageniti Core",
url: "https://ageniti.dev",
docsUrl: "https://ageniti.dev/docs",
},
docs: {
summary: "Use this app to create tasks and inspect status.",
},
actions,
services,
permissionChecker,
middleware,
adapters,
build,
});Options:
name: required app nameattribution: optional source attribution metadata for CLI help, MCP manifests, tool metadata, generated guides, and bundle artifactsactions: array of Ageniti actionsservices: shared services injected intocontext.servicespermissionChecker: authorisation hookmiddleware: runtime middleware chainadapters: custom surface adapter list for manifest generationbuild: default build settings reused byapp.build()and CLI build commands
attribution is descriptive metadata, not telemetry. Use it when you want generated surfaces to show product origin or branding information in a structured way.
Returned members:
nameactionsadaptersruntimemanifest(options?)actionManifest()lint()build()package()publish()createGuideDoc()exportDocs()createCli()createJsonRunner()createHttpHandler()createHttpServer()createMcpHandler()createMcpManifest()createOpenAITools()createOpenAIResponsesTools()createAISDKTools()createFunctionCallingManifest()createReactAdapter()createDevServer()
Use createAgenitiApp() when you want one app definition and convenient access to every supported surface.
createRuntime(options)
Creates the headless runtime used by all app capability surfaces.
Options:
actionsservicespermissionCheckermiddlewarehooksredactidempotencyCacheidempotencyTtlMsidempotencyMaxEntries
Returned API:
registry:Map<string, Action>listActions({ surface? })invoke(actionOrName, input?, invokeOptions?)stream(actionOrName, input?, invokeOptions?)
invokeOptions supports:
invocationIdsurfaceuserauthenvservicesmetadatasignaltimeoutMsretryconfirmidempotencyKey
The runtime is responsible for:
- action lookup
- supported surface checks
- input validation
- confirmation checks
- permission checks
- middleware execution
- timeout and retry
- output serialisation and output validation
- success and failure envelopes
Read Runtime Semantics for the full execution model.
Manifest And Registry Helpers
createActionRegistry(actions)
Builds a Map keyed by action name and throws on duplicates.
createActionManifest(actions)
Returns a plain array describing the public action contract, including schemas, visibility, confirmation, and publicMetadata. This helper is useful for inspection, tooling, tests, or custom wrappers.
describeAction(action)
import { describeAction } from "@ageniti/core/manifest";Normalises a single action into a manifest-friendly object.
createSurfaceManifest({ appName, actions, adapters })
import { createSurfaceManifest } from "@ageniti/core/manifest";Returns a manifest object with:
- app name
- generation timestamp
- action descriptions
- surface descriptions and capabilities
CLI API
createCli(options)
Creates a CLI object.
const cli = createCli({
name: "task-app",
attribution: {
text: "Powered by Ageniti",
},
actions,
runtime,
runtimeOptions,
env,
adapters,
buildOptions,
});Returned members:
nameactionsruntimerun(argv?, io?)main(argv?, io?)
Built-in commands:
<app> <action> [options]
<app> <action> --json '{"field":"value"}'
<app> <action> --schema
<app> actions
<app> manifest
<app> diff --previous old.json --next new.json
<app> build [manifest|cli|mcp|docs|bundle] [options]
<app> docs [options]
<app> package [options]
<app> publish [options]
<app> init <react|expo|next|host-openai|host-ai-sdk|host-mcp|host-http> [options]
<app> doctor [options]
<app> lint
<app> mcp
<app> mcp --stdio
<app> dev --port 4321Input behaviour:
- snake_case actions can also be called as kebab-case commands
- boolean flags accept
--flag,--flag true, or--no-flag - array, object, and
anyinputs are parsed from JSON strings - runtime confirmation maps to
--confirm
Build command options:
--out-dir <dir>--app-module <module-path>--app-export <name>--package-json--cwd <dir>--filename <name>fordocs
Launcher targets need a Node-safe app module so the generated files know what to import. If --app-module is omitted, Ageniti tries to discover a default entry such as ./src/ageniti/app.js.
JSON Runner API
createJsonRunner(options)
Creates a small structured invocation wrapper.
const runner = createJsonRunner({ actions, runtime, runtimeOptions });Returned API:
runtimeinvoke(payload)
Payload fields:
actioninputconfirmuserauthmetadata
If the payload is not an object, the runner returns INVALID_JSON_RUNNER_PAYLOAD.
MCP API
createMcpManifest(actions, options)
Returns:
{
tools: [
{
name,
title,
description,
inputSchema,
metadata,
},
],
}Filtering rules:
- action must support the
mcpsurface - private actions are excluded unless
includePrivate: true - local actions are excluded unless
includeLocal: true - destructive actions are excluded unless
includeDestructive: true
createMcpHandler(options)
Creates a JSON-RPC handler for tools/list and tools/call.
const handle = createMcpHandler({
actions,
runtime,
runtimeOptions,
includePrivate,
includeDestructive,
});tools/call returns both a text block and structuredContent containing the runtime result.
When a destructive tool is intentionally exposed with includeDestructive: true, callers still need params.confirm: true for execution.
createMcpStdioServer(options)
Creates a stdio transport around createMcpHandler() with automatic newline and Content-Length framing support.
await createMcpStdioServer({ actions, runtime }).start();Use this when another process expects JSON-RPC over stdio. Ageniti auto-detects newline-delimited and Content-Length framed requests.
LLM Tool Adapters
createOpenAITools(actions, options)
Returns Chat Completions-style function tools.
createOpenAIResponsesTools(actions, options)
Returns Responses-style function tools.
createAISDKTools(actions, options)
Returns a Vercel AI SDK-style tools object.
const tools = createAISDKTools(actions, {
runtime,
returnEnvelope: true,
});Each tool contains:
descriptionparameters: Ageniti schema objectinputSchema: JSON Schema representationexecute(input, options?)
createFunctionCallingManifest(actions, options)
Returns a combined summary:
openaiChatToolsopenaiResponsesToolsaiSdkToolsas action names
Shared adapter options:
runtimestrictincludePrivateincludeLocalincludeDestructivesurfacereturnEnvelopefilter
Filtering rules:
- action must support the selected surface, default
ai-sdk - private actions are excluded unless
includePrivate: true - local actions are excluded unless
includeLocal: true - destructive actions are excluded unless
includeDestructive: true filter(action)can apply additional filtering
React API
createReactActionAdapter(options)
Creates a React-friendly wrapper over the shared runtime.
const { runtime, useAction } = createReactActionAdapter({ actions, runtime });useAction(action) returns an async function that invokes the action with surface: "react".
Dev Server API
createDevServer(options)
Creates the local dev console server.
const devServer = createDevServer({
name: "task-app",
actions,
runtime,
});
const listener = await devServer.listen(4321, "127.0.0.1");Routes:
GET /: HTML dev consoleGET /api/actions: action manifest for the dev surfacePOST /api/actions/:name/invoke: invoke one action
HTTP API
app.createHttpHandler(options)
Creates a framework-friendly HTTP JSON handler. Request body auth / user fields are ignored by default; inject trusted identity on the request object or via resolveContext.
const handle = app.createHttpHandler();
const response = await handle({
method: "POST",
path: "/ageniti/actions/create_task/invoke",
body: {
input: {
title: "Follow up with design review",
priority: "high",
},
},
});Routes:
GET /ageniti/actionsPOST /ageniti/actions/:name/invoke
app.createHttpServer(options)
Creates a small Node HTTP server around the same handler.
const server = app.createHttpServer();
const listener = await server.listen(4322);HTTP actions must support the http surface. Private, local, and destructive actions are filtered out by default.
Server-only options:
maxBodyBytesrequireJsonContentType
Build API
import { buildArtifacts, packageArtifacts, publishArtifacts } from "@ageniti/core/build";
import { createGuideDoc, exportDocs } from "@ageniti/core/docs";The app.build(), app.package(), app.publish(), app.createGuideDoc(), and app.exportDocs() methods on the result of createAgenitiApp() continue to work unchanged.
app.build(options)
Builds official Ageniti distribution artifacts from an app object.
await app.build({
targets: ["bundle"],
appModule: "./src/ageniti/app.js",
appExport: "app",
outDir: "./dist/ageniti",
});Common options:
targets:manifest,cli,mcp,docs, orbundleoutDir: output directory, defaultdist/agenitiappModule: headless Node-safe module that exports your appappExport: export name, defaultappincludePackageJson: force a generatedpackage.jsoncwd: working directory used for path resolutionfilename: custom file name fordocs, defaultGUIDE.md
bundle expands to:
ageniti.manifest.jsonageniti.actions.jsoncli.mjsmcp-stdio.mjsageniti.mcp.jsonGUIDE.mdpackage.jsonREADME.mdageniti.bundle.json
The generated README.md is part of the app distribution. It explains how to run the CLI locally, publish the generated package, install the resulting bin, connect MCP clients, and deploy HTTP through your own backend.
app.createGuideDoc(options)
Returns one Markdown guide string.
const markdown = app.createGuideDoc();It reads the app description / docs, plus each action's description, permissions, side effects, surfaces, publicMetadata, and docs.
app.exportDocs(options)
Writes a unified guide document to disk.
await app.exportDocs({
outDir: "./dist/ageniti",
});Default output:
GUIDE.md
The same capability is available through the CLI:
task-app docs
task-app docs --out-dir ./dist/ageniti
task-app build docs --out-dir ./dist/agenitiapp.package(options)
Builds a bundle and then runs npm pack in the generated output directory.
const result = await app.package({
appModule: "./src/ageniti/app.js",
outDir: "./dist/ageniti",
});The result includes:
outDirpackageDirpackageFilebuild
app.publish(options)
Builds a bundle, runs npm pack, and then runs npm publish.
const result = await app.publish({
appModule: "./src/ageniti/app.js",
outDir: "./dist/ageniti",
dryRun: true,
access: "public",
});Important defaults:
dryRundefaults totrue- pass
dryRun: falseonly for a real publish
Deployment shapes:
- CLI package: publish or distribute the generated npm package and expose its
bin. - MCP server: run
mcp-stdio.mjslocally or the generated<bin-name>-mcpcommand after install. - HTTP gateway: mount
app.createHttpHandler()in your own backend; Ageniti does not require a hosted runtime.
The returned result includes:
okoutDirpackageDirpackageFilepublishedstdoutstderrbuild
buildArtifacts(options)
Lower-level build helper used by app.build().
packageArtifacts(options)
Lower-level packaging helper used by app.package().
const result = await packageArtifacts({
appName: "task-app",
actions,
adapters,
appModule: "./src/ageniti/app.js",
appExport: "app",
});The result includes:
okoutDirpackageDirpackageFilebuild
publishArtifacts(options)
Lower-level publish helper used by app.publish().
const result = await publishArtifacts({
appName: "task-app",
actions,
adapters,
appModule: "./src/ageniti/app.js",
appExport: "app",
dryRun: true,
});The result includes:
okoutDirpackageDirpackageFilepublishedstdoutstderrbuild
Manifest Diff
import { diffActionManifests } from "@ageniti/core/manifest";diffActionManifests(previous, next)
Compares two action manifests or surface manifests and reports breaking changes, warnings, and informational changes.
const diff = diffActionManifests(previousManifest, nextManifest);Breaking changes include removed actions and input/output schema changes.
const result = await buildArtifacts({
appName: "task-app",
actions,
adapters,
targets: ["bundle"],
appModule: "./src/ageniti/app.js",
appExport: "app",
});Use this helper when you want to build launchers or manifests without first constructing an app object.
Project Tools
import {
initProject,
doctorProject,
loadProjectConfig,
findDefaultAppModule,
detectTypeScriptRuntime,
supportsTypeScriptEntrypoints,
} from "@ageniti/core/project";initProject(options)
Scaffolds a headless Ageniti entry for app projects, including react, expo, next, and host starter templates such as host-openai, host-ai-sdk, host-mcp, and host-http.
const result = await initProject({
cwd: process.cwd(),
template: "react",
});The result includes:
oktemplatecwdfilesappModulenextSteps
doctorProject(options)
Inspects a project for framework type, default Ageniti entry discovery, and common launcher or build issues.
const result = await doctorProject({ cwd: process.cwd() });The result includes:
okkindcwddefaultAppModulechecksrecommendations
findDefaultAppModule(options)
Finds the default Node-safe Ageniti app entry used by zero-config build flows.
const result = await findDefaultAppModule({ cwd: process.cwd() });Possible outcomes include:
found: truewithmodulePathand reasonnode-safe-defaultfound: truewithmodulePathand reasonconfiguredfound: falsewith reasontypescript-only-entryfound: falsewith reasonmissing
loadProjectConfig(options)
Loads ageniti.config.json, ageniti.config.js, ageniti.config.mjs, or ageniti.config.cjs from a project root.
const config = await loadProjectConfig({ cwd: process.cwd() });Returned fields may include:
build.appModulebuild.appExportbuild.outDirbuild.includePackageJsonbuild.typescriptRuntimemcp.transportmcp.envpackage.namepackage.versionpackage.descriptionpackage.privatepackage.binNameconfigPath
detectTypeScriptRuntime(options)
Detects whether the current project is configured to generate TypeScript launchers.
const runtime = detectTypeScriptRuntime({ packageJson, config });Current built-in support:
- returns
tsxwhentsxis configured or installed - returns
undefinedwhen no supported TypeScript runtime is available
supportsTypeScriptEntrypoints(options)
Returns whether the current project can generate launcher files from a TypeScript-only headless app entry.
const supported = supportsTypeScriptEntrypoints({ packageJson, config });Surface Adapter API
defineSurfaceAdapter(adapter)
Creates a custom adapter description.
Required field:
name
Defaulted fields:
description: ""capabilities: {}canExpose: () => truedescribe: (action) => action
Built-In Adapters
cliAdapterjsonAdapterhttpAdaptermcpAdapterreactAdapterdevAdapteraiSdkAdapter
defaultSurfaceAdapters()
Returns the built-in adapter list used by createAgenitiApp() and createCli().
findAdapter(adapters, name)
Finds one adapter by name.
Lint API
import { lintActions } from "@ageniti/core/lint";lintActions(actions)
Runs static checks against action definitions.
Current findings include:
- duplicate action names
- invalid action naming
- weak descriptions
- destructive MCP exposure
- unspecified idempotency on write or destructive actions
- non-object input shapes
- write or destructive actions without permissions
Schema API
s
Lightweight schema builder.
Available builders:
s.string()s.number()s.boolean()s.enum(values)s.array(schema)s.object(shape)s.literal(value)s.union(schemas)s.record(schema)s.any()
Common modifiers:
.describe(text).default(value).optional().nullable().meta(data)
Type-specific helpers:
- string:
.min(),.max(),.pattern(),.url(),.datetime() - number:
.min(),.max(),.int() - object:
.passthrough()
toJSONSchema(schema)
Converts an Ageniti schema into JSON Schema.
SchemaValidationError
Thrown by schema parsing paths when validation fails.
Error And Result Types
AgenitiError
Custom runtime error with:
codeissuesretryable
Runtime Result Shape
Success:
{
"ok": true,
"data": {},
"artifacts": [],
"logs": [],
"meta": {
"action": "create_task",
"invocationId": "invocation-id",
"surface": "cli",
"durationMs": 12
}
}Failure:
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid action input.",
"issues": [],
"retryable": false
},
"artifacts": [],
"logs": [],
"meta": {
"action": "create_task",
"invocationId": "invocation-id",
"surface": "mcp",
"durationMs": 3
}
}Bulk Registration
defineActions(map, options?)
Register a record of actions in one call. CamelCase keys are normalized to snake_case action names.
import { defineActions, s } from "@ageniti/core";
export const actions = defineActions({
createTask: {
description: "Create a task.",
input: s.object({ title: s.string() }),
run: async ({ title }) => ({ id: crypto.randomUUID(), title }),
},
ping: () => ({ ok: true }),
});Options:
defaults: shared config applied to every entryrename(key): custom name strategy
actionFromHandler(handler, config)
Wrap a single existing function as an action. Handlers can be 1-arg
(input) or 2-arg (input, ctx) — Ageniti detects and forwards correctly.
actionsFromHandlers(handlers, metadata?)
Pair a record of plain functions with metadata.
import * as handlers from "./app/actions/tasks";
import { actionsFromHandlers, s } from "@ageniti/core";
export const actions = actionsFromHandlers(handlers, {
createTask: { description: "Create a task.", input: s.object({ title: s.string() }) },
});Schema Interop
wrapSchema(foreign, options?)
Wrap any Zod-style schema (.safeParse / .parse) or Standard Schema v1 as
an Ageniti Schema. JSON Schema is generated through best-effort
introspection; pass { jsonSchema } to override.
assertSchema (used internally by defineAction) auto-wraps foreign
schemas, so you usually never call wrapSchema directly.
s.object(shape).strict()
Reject unknown properties at validation time (companion to .passthrough()).
Streaming Events
runtime.stream(actionOrName, input, options?)
Returns an AsyncIterableIterator<RuntimeStreamEvent> that yields events
as the action runs:
type RuntimeStreamEvent =
| { type: "log"; level: string; message: string; time: string; fields: Record<string, unknown> }
| { type: "artifact"; artifact: Artifact }
| { type: "progress"; message?: string; percent?: number; fields?: Record<string, unknown>; time: string }
| { type: "result"; envelope: RuntimeResult };Events come from ctx.logger.*, ctx.progress.report(), and
ctx.artifacts.add() inside run(). The stream always ends with one
result event.
Typed Client
createClient(options)
import { createClient } from "@ageniti/core/client";
// In-process
const client = createClient({ runtime });
const task = await client.create_task({ title: "Hello" });
// Remote
const remote = createClient({ url: "https://api.example.com" });Special methods:
client.$invoke(name, input, options?)— typed invocation by stringclient.$stream(name, input, options?)— async iterable of eventsclient.$transport— underlying transport object
Notes:
- Remote HTTP clients can send
metadata,confirm, andidempotencyKeyin the request body. - Remote HTTP clients cannot send trusted
userorauthin the request body. Use headers / customfetchand resolve identity withresolveContexton the server. - Transport failures and invalid remote responses also throw
AgenitiClientError, with client-side codes such asTRANSPORT_ERRORorINVALID_RESPONSE.
AgenitiClientError
Thrown on failure with code, issues, retryable, and optional envelope. Transport-level failures also use this error type.
generateClientTypes(actions, options?)
Generate a TypeScript .d.ts from an action manifest:
import { generateClientTypes } from "@ageniti/core/client-gen";
import { writeFile } from "node:fs/promises";
await writeFile(".ageniti/client.d.ts", generateClientTypes(actions, {
interfaceName: "TasksClient",
}));React Hook
useAction(action, { runtime })
State machine hook. Subscribes to runtime.stream so logs / progress /
artifacts update live. Imported from @ageniti/core/react-hooks.
State shape: { status, data, error, logs, artifacts, progress, invoke, cancel, reset }.
Component unmount auto-aborts; new invoke() calls cancel the previous one.
Test Utilities
import {
createTestRuntime, expectOk, expectError, expectLog,
collectStream, stubAction,
} from "@ageniti/core/test-utils";
const t = createTestRuntime([myAction], {
services: { db: stubDb },
allow: true, // or "denied reason" or async permission checker
});
const env = await t.invoke("my_action", { x: 1 });
expectOk(env);Runtime Hooks & Redaction
const runtime = createRuntime({
actions,
hooks: {
onInvocationStart: ({ action, invocationId, input }) => metrics.timer.start(invocationId),
onInvocationEnd: ({ action, invocationId, envelope }) => metrics.timer.end(invocationId, envelope.ok),
},
redact: { keys: ["ssn", "credit_card"], placeholder: "[REDACTED]" },
idempotencyMaxEntries: 5000,
idempotencyTtlMs: 10 * 60 * 1000,
});Default redaction keys: password, passwd, secret, token, apikey,
api_key, authorization, cookie, session, x-api-key,
access_token, refresh_token, private_key, client_secret.
Error messages and issue text additionally have known token shapes redacted
(Bearer …, JWT, sk-…, ghp_…, xoxb-…, key=value).
Error Codes
| Code | HTTP | CLI exit | When |
|---|---|---|---|
| VALIDATION_ERROR | 400 | 2 | input failed schema |
| OUTPUT_VALIDATION_ERROR | 502 | 2 | run returned invalid output |
| OUTPUT_SERIALIZATION_ERROR | 502 | 2 | run returned non-JSON-safe value |
| AUTHENTICATION_ERROR | 401 | 3 | missing credentials |
| AUTHORIZATION_ERROR | 403 | 3 | permission denied |
| CONFIRMATION_REQUIRED | 409 | 3 | destructive action without confirm |
| ACTION_NOT_FOUND | 404 | 4 | unknown action |
| UNSUPPORTED_SURFACE | 405 | 4 | action not on this surface |
| RATE_LIMITED | 429 | 5 | upstream rate limit |
| CONCURRENCY_LIMIT | 429 | 5 | per-action limit hit (retryable) |
| EXTERNAL_SERVICE_ERROR | 502 | 5 | upstream failure |
| TIMEOUT | 504 | 124 | exceeded timeoutMs |
| CANCELLED | 499 | 130 | user/runtime aborted |
| CONFLICT | 409 | 1 | optimistic concurrency / state conflict |
| INTERNAL_ERROR | 500 | 1 | uncaught run failure |