{"_id":"@ageniti/core","_rev":"3-1a3d3474b3749f7a4436ff5437a602ea","name":"@ageniti/core","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@ageniti/core","version":"0.1.0","keywords":["agents","mcp","cli","actions","react","automation","tools"],"author":{"name":"Ageniti contributors"},"license":"MIT","_id":"@ageniti/core@0.1.0","maintainers":[{"name":"yiliu.li","email":"yiliu.li@outlook.com"}],"bin":{"ageniti":"bin/ageniti.mjs"},"dist":{"shasum":"adaffa4cf2064490359a8eaefa2b806dd17a8eb5","tarball":"https://registry.npmjs.org/@ageniti/core/-/core-0.1.0.tgz","fileCount":33,"integrity":"sha512-vTfpR/P4ZgRsCanL7DlmrmIeB5ufer3UxBzQPy25HsE5bC4NPfMu/y4p+bqVipN4Jq9CmnDVHzemYAzMyandHw==","signatures":[{"sig":"MEUCIG2c/EbbDippkFDZOh5KvD2Rw1CX3Y4VK3PHHUXjycHjAiEAu4iYYxSa0ZT6nRrl4KanxHHrDx7RaKZi5APwKlp+Fbg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":179303},"type":"module","types":"./src/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./src/index.d.ts","default":"./src/index.js"},"./app":{"types":"./src/index.d.ts","default":"./src/app.js"},"./cli":{"types":"./src/index.d.ts","default":"./src/cli.js"},"./dev":{"types":"./src/index.d.ts","default":"./src/dev-server.js"},"./mcp":{"types":"./src/index.d.ts","default":"./src/mcp.js"},"./core":{"types":"./src/index.d.ts","default":"./src/core.js"},"./http":{"types":"./src/index.d.ts","default":"./src/http.js"},"./lint":{"types":"./src/index.d.ts","default":"./src/lint.js"},"./react":{"types":"./src/index.d.ts","default":"./src/react.js"},"./ai-sdk":{"types":"./src/index.d.ts","default":"./src/ai-sdk.js"},"./schema":{"types":"./src/index.d.ts","default":"./src/schema.js"},"./adapters":{"types":"./src/index.d.ts","default":"./src/adapters.js"},"./manifest":{"types":"./src/index.d.ts","default":"./src/manifest.js"},"./json-runner":{"types":"./src/index.d.ts","default":"./src/json-runner.js"},"./package.json":"./package.json"},"private":false,"scripts":{"demo":"node examples/demo.cli.js","test":"node --test","example":"node examples/hello.cli.js","prepack":"npm test","demo:dev":"node examples/demo.cli.js dev --port 4321","demo:mcp":"node examples/demo.cli.js mcp --stdio","pack:dry":"npm pack --dry-run","example:mcp":"node examples/hello.cli.js mcp","example:schema":"node examples/hello.cli.js hello --schema"},"_npmUser":{"name":"yiliu.li","email":"yiliu.li@outlook.com"},"_npmVersion":"11.11.0","description":"Expose React and TypeScript app actions as CLI, HTTP, MCP, OpenAI, and AI SDK tools without restructuring your app.","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/core_0.1.0_1777761135501_0.5368287040653013","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ageniti/core","version":"0.1.1","keywords":["agents","mcp","cli","actions","react","automation","tools"],"author":{"name":"Ageniti contributors"},"license":"MIT","_id":"@ageniti/core@0.1.1","maintainers":[{"name":"yiliu.li","email":"yiliu.li@outlook.com"}],"homepage":"https://ageniti.dev","bugs":{"url":"https://github.com/Ageniti/ageniti/issues"},"bin":{"ageniti":"bin/ageniti.mjs"},"dist":{"shasum":"29d6c244727fe986541cc9e7df98244350e75746","tarball":"https://registry.npmjs.org/@ageniti/core/-/core-0.1.1.tgz","fileCount":40,"integrity":"sha512-pxYmip7zEcPOi7OeaDs0SIZLpjLorILiMRm1Z6RuWIV2GJTfup3XSM+URZ/xgFN2DTWxIBNSz+8zd41ksvn3Xg==","signatures":[{"sig":"MEUCIQDO6vRT9hrCuI+oMEmUJzfhqGGmdvXHuWJAQRr6KGQUEgIgAT76mfflgmJCry7XsE/bOW7o53p9gPuEO6XA/Xqt8gw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":204853},"type":"module","types":"./src/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./src/index.d.ts","default":"./src/index.js"},"./app":{"types":"./src/index.d.ts","default":"./src/app.js"},"./cli":{"types":"./src/index.d.ts","default":"./src/cli.js"},"./dev":{"types":"./src/index.d.ts","default":"./src/dev-server.js"},"./mcp":{"types":"./src/index.d.ts","default":"./src/mcp.js"},"./core":{"types":"./src/index.d.ts","default":"./src/core.js"},"./http":{"types":"./src/index.d.ts","default":"./src/http.js"},"./lint":{"types":"./src/index.d.ts","default":"./src/lint.js"},"./react":{"types":"./src/index.d.ts","default":"./src/react.js"},"./ai-sdk":{"types":"./src/index.d.ts","default":"./src/ai-sdk.js"},"./schema":{"types":"./src/index.d.ts","default":"./src/schema.js"},"./adapters":{"types":"./src/index.d.ts","default":"./src/adapters.js"},"./manifest":{"types":"./src/index.d.ts","default":"./src/manifest.js"},"./json-runner":{"types":"./src/index.d.ts","default":"./src/json-runner.js"},"./package.json":"./package.json"},"gitHead":"12acf86d5cb41765122e52d31b2bef89043973bf","private":false,"scripts":{"demo":"node examples/demo.cli.js","test":"node --test","example":"node examples/hello.cli.js","prepack":"npm test","demo:dev":"node examples/demo.cli.js dev --port 4321","demo:mcp":"node examples/demo.cli.js mcp --stdio","pack:dry":"npm pack --dry-run","example:mcp":"node examples/hello.cli.js mcp","example:http":"node examples/http-gateway.js","example:ai-sdk":"node examples/ai-sdk-route.js","example:schema":"node examples/hello.cli.js hello --schema","example:mcp-host":"node examples/mcp-host.js","example:responses":"node examples/openai-responses-host.js"},"_npmUser":{"name":"yiliu.li","email":"yiliu.li@outlook.com"},"repository":{"url":"git+https://github.com/Ageniti/ageniti.git","type":"git"},"_npmVersion":"11.11.0","description":"Expose React and TypeScript app actions as CLI, HTTP, MCP, OpenAI, and AI SDK tools without restructuring your app.","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/core_0.1.1_1777802967765_0.4970378334362411","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@ageniti/core","version":"0.1.2","description":"Expose React and TypeScript app actions as CLI, HTTP, MCP, OpenAI, and AI SDK tools without restructuring your app.","type":"module","private":false,"license":"MIT","author":{"name":"Ageniti contributors"},"homepage":"https://ageniti.dev","repository":{"type":"git","url":"git+https://github.com/Ageniti/ageniti.git"},"bugs":{"url":"https://github.com/Ageniti/ageniti/issues"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"bin":{"ageniti":"bin/ageniti.mjs"},"keywords":["agents","mcp","cli","actions","react","automation","tools"],"sideEffects":false,"types":"./src/index.d.ts","exports":{".":{"types":"./src/index.d.ts","default":"./src/index.js"},"./ai-sdk":{"types":"./src/types/subpaths.d.ts","default":"./src/ai-sdk.js"},"./adapters":{"types":"./src/types/subpaths.d.ts","default":"./src/adapters.js"},"./app":{"types":"./src/types/subpaths.d.ts","default":"./src/app.js"},"./cli":{"types":"./src/types/subpaths.d.ts","default":"./src/tooling/cli.js"},"./core":{"types":"./src/types/subpaths.d.ts","default":"./src/runtime/core.js"},"./dev":{"types":"./src/types/subpaths.d.ts","default":"./src/dev-server.js"},"./http":{"types":"./src/types/subpaths.d.ts","default":"./src/transports/http.js"},"./manifest":{"types":"./src/types/subpaths.d.ts","default":"./src/runtime/manifest.js"},"./json-runner":{"types":"./src/types/subpaths.d.ts","default":"./src/json-runner.js"},"./lint":{"types":"./src/types/subpaths.d.ts","default":"./src/tooling/lint.js"},"./mcp":{"types":"./src/types/subpaths.d.ts","default":"./src/transports/mcp.js"},"./react":{"types":"./src/types/subpaths.d.ts","default":"./src/react.js"},"./react-hooks":{"types":"./src/types/subpaths.d.ts","default":"./src/react-hooks.js"},"./schema":{"types":"./src/types/subpaths.d.ts","default":"./src/schema/schema.js"},"./client":{"types":"./src/types/subpaths.d.ts","default":"./src/clients/client.js"},"./client-gen":{"types":"./src/types/subpaths.d.ts","default":"./src/clients/client-gen.js"},"./test-utils":{"types":"./src/types/subpaths.d.ts","default":"./src/testing/test-utils.js"},"./handlers":{"types":"./src/types/subpaths.d.ts","default":"./src/runtime/handlers.js"},"./schema-adapter":{"types":"./src/types/subpaths.d.ts","default":"./src/schema/schema-adapter.js"},"./package.json":"./package.json"},"scripts":{"ci":"npm test && npm pack --dry-run --ignore-scripts --cache ./.npm-cache","test":"node --test","prepack":"npm test","pack:dry":"npm test && npm pack --dry-run --ignore-scripts --cache ./.npm-cache","example":"node examples/hello.cli.js","demo":"node examples/demo.cli.js","demo:dev":"node examples/demo.cli.js dev --port 4321","demo:mcp":"node examples/demo.cli.js mcp --stdio","example:responses":"node examples/openai-responses-host.js","example:ai-sdk":"node examples/ai-sdk-route.js","example:http":"node examples/http-gateway.js","example:mcp-host":"node examples/mcp-host.js","example:schema":"node examples/hello.cli.js hello --schema","example:mcp":"node examples/hello.cli.js mcp"},"engines":{"node":">=20"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"gitHead":"db92c0acfc393d6c95932421fc09286f104a1d05","_id":"@ageniti/core@0.1.2","_nodeVersion":"25.8.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-exuq7Ufqn5tf8jEvUnqfgTZatZ3e/JWO0ry67UM54gkkbZjD4eSiBGhAsyTo8m2S98q4HPp4DZ8H1TJmzVZs4g==","shasum":"d5ce5bbeebd8ab8be3f5a01421efd632707ac64d","tarball":"https://registry.npmjs.org/@ageniti/core/-/core-0.1.2.tgz","fileCount":54,"unpackedSize":326108,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIChcqqZm2lVb4XaJKLHS+MTkkxM2nBd4ohTLY2VsY8/RAiEAml9mQWGEkW+hNyboPlVB7Je7r7yOzz38a5EfMWy37Yo="}]},"_npmUser":{"name":"yiliu.li","email":"yiliu.li@outlook.com"},"directories":{},"maintainers":[{"name":"yiliu.li","email":"yiliu.li@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.1.2_1778153503675_0.7360642667278516"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-02T22:32:15.386Z","modified":"2026-05-07T11:31:43.990Z","0.1.0":"2026-05-02T22:32:15.668Z","0.1.1":"2026-05-03T10:09:27.894Z","0.1.2":"2026-05-07T11:31:43.820Z"},"bugs":{"url":"https://github.com/Ageniti/ageniti/issues"},"author":{"name":"Ageniti contributors"},"license":"MIT","homepage":"https://ageniti.dev","keywords":["agents","mcp","cli","actions","react","automation","tools"],"repository":{"type":"git","url":"git+https://github.com/Ageniti/ageniti.git"},"description":"Expose React and TypeScript app actions as CLI, HTTP, MCP, OpenAI, and AI SDK tools without restructuring your app.","maintainers":[{"name":"yiliu.li","email":"yiliu.li@outlook.com"}],"readme":"<p align=\"center\">\n  <a href=\"https://ageniti.dev\">\n    <img src=\"assets/logo.svg\" alt=\"Ageniti logo\" width=\"96\" height=\"96\">\n  </a>\n</p>\n\n<h1 align=\"center\">Ageniti</h1>\n\n<p align=\"center\">\n  <strong>The action primitive for apps that need to be callable by agents.</strong>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@ageniti/core\"><img alt=\"npm version\" src=\"https://img.shields.io/npm/v/@ageniti/core?style=flat-square\"></a>\n  <a href=\"https://www.npmjs.com/package/@ageniti/core\"><img alt=\"npm downloads\" src=\"https://img.shields.io/npm/dm/@ageniti/core?style=flat-square\"></a>\n  <a href=\"https://github.com/Ageniti/ageniti/blob/main/LICENSE\"><img alt=\"license\" src=\"https://img.shields.io/npm/l/@ageniti/core?style=flat-square\"></a>\n  <a href=\"https://www.npmjs.com/package/@ageniti/core\"><img alt=\"node\" src=\"https://img.shields.io/node/v/@ageniti/core?style=flat-square\"></a>\n  <a href=\"https://github.com/Ageniti/ageniti\"><img alt=\"module format\" src=\"https://img.shields.io/badge/module-ESM-black?style=flat-square\"></a>\n  <a href=\"https://discord.gg/cmkxR7GcYu\"><img alt=\"discord\" src=\"https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord&logoColor=white\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://ageniti.dev\">Website</a>\n  ·\n  <a href=\"https://github.com/Ageniti/ageniti\">GitHub</a>\n  ·\n  <a href=\"https://www.npmjs.com/package/@ageniti/core\">npm</a>\n  ·\n  <a href=\"docs/getting-started.md\">Getting Started</a>\n  ·\n  <a href=\"docs/api.md\">API</a>\n</p>\n\nAgeniti is the action primitive layer for apps that need to expose\ncapabilities to agents, automation systems, and external tools. You define an\naction once — input contract, output contract, side effects, permissions —\nand any caller (CLI, HTTP, MCP, OpenAI / AI SDK tools, React UI, your own\ntyped client) can invoke it through the same runtime, with the same\nstreaming events, the same redaction, the same error contract.\n\n## Why Ageniti\n\nModern apps want to be callable not just from people but from agents, scripts,\nand other apps. Today every entry point comes with its own glue: argv parsing,\nschema validation, tool descriptions, permission checks, log redaction, error\nshapes, idempotency, cancellation. Each surface re-implements the same things\ninconsistently.\n\nAgeniti collapses all of that into one concept. Each action you declare runs\nthrough a single runtime that handles the cross-cutting concerns. Each surface\nis a thin adapter over the same contract. Streaming events let any consumer —\nagent caller, UI, log shipper — observe the action live without owning it.\n\n## Install\n\n```bash\nnpm i @ageniti/core\n```\n\nSubpath exports:\n\n| Subpath | What it gives you |\n|---|---|\n| `@ageniti/core` | Main authoring API plus packaging/project helpers such as `buildArtifacts`, `packageArtifacts`, `publishArtifacts`, `createGuideDoc`, `exportDocs`, `initProject`, `doctorProject`, and `detectTypeScriptRuntime` |\n| `@ageniti/core/ai-sdk` | `createOpenAITools`, `createOpenAIResponsesTools`, `createAISDKTools`, `createFunctionCallingManifest` |\n| `@ageniti/core/adapters` | Built-in surface adapters and helpers such as `httpAdapter`, `mcpAdapter`, `aiSdkAdapter`, `cliAdapter`, `jsonAdapter`, `reactAdapter`, `devAdapter`, `defaultSurfaceAdapters`, `defineSurfaceAdapter`, and `findAdapter` |\n| `@ageniti/core/app`, `/core`, `/cli`, `/mcp`, `/dev`, `/manifest`, `/json-runner`, `/lint` | Narrow imports for the corresponding runtime or surface modules |\n| `@ageniti/core/http` | `createHttpHandler`, `createHttpServer`, `parseRequestBody`, `sendJson`, `sendText` |\n| `@ageniti/core/handlers` | `defineActions`, `actionFromHandler`, `actionsFromHandlers` |\n| `@ageniti/core/schema-adapter` | `wrapSchema`, Zod / Standard Schema v1 interop |\n| `@ageniti/core/schema` | Schema helpers only |\n| `@ageniti/core/client` | `createClient`, `AgenitiClientError` |\n| `@ageniti/core/client-gen` | `generateClientTypes`, `jsonSchemaToTs` |\n| `@ageniti/core/test-utils` | `createTestRuntime`, `expectOk`, `expectError`, `expectLog`, `collectStream`, `stubAction` |\n| `@ageniti/core/react` | `createReactActionAdapter`, `makeInvoker`, `streamAction` (no React import) |\n| `@ageniti/core/react-hooks` | `useAction` — full state-machine hook (React peer dep) |\n| `@ageniti/core/package.json` | Package metadata for tooling that needs to inspect the published package |\n\n## The 5 Core Primitives\n\n### 1. The Action Contract\n\n```ts\nimport { defineAction, s } from \"@ageniti/core\";\n\nexport const createTask = defineAction({\n  name: \"create_task\",\n  description: \"Create a task in the user's inbox.\",\n  sideEffects: \"write\",\n  idempotency: \"conditional\",\n  input: s.object({\n    title: s.string().min(1),\n    priority: s.enum([\"low\", \"high\"]).default(\"low\"),\n  }),\n  output: s.object({ id: s.string(), title: s.string() }),\n  async run({ title, priority }, ctx) {\n    ctx.logger.info(\"Creating task\", { title });\n    const task = await ctx.services.tasks.create({ title, priority });\n    return { id: task.id, title: task.title };\n  },\n});\n```\n\nThe contract is the source of truth. Every surface — CLI flags, MCP tool\ndefinition, OpenAI tool spec, HTTP route, React hook, typed client — is\nderived from it. You never describe the same action twice.\n\n### 2. Bring Your Own Schema\n\nYou don't have to use `s.*`. Zod, Valibot, ArkType, anything that quacks\nlike Standard Schema v1 just works:\n\n```ts\nimport { z } from \"zod\";\nimport { defineAction } from \"@ageniti/core\";\n\nexport const search = defineAction({\n  name: \"search_tasks\",\n  description: \"Search for tasks matching a query.\",\n  input: z.object({ query: z.string(), limit: z.number().int().optional() }),\n  output: z.object({ results: z.array(z.object({ id: z.string(), title: z.string() })) }),\n  async run({ query, limit }) {\n    return { results: await tasks.search(query, limit ?? 20) };\n  },\n});\n```\n\nAgeniti detects foreign schemas (anything with `.safeParse` / `.parse` /\n`\"~standard\".validate`) and wraps them transparently. JSON Schema for MCP\nand OpenAI tool descriptions is generated from the wrapped schema.\n\n### 3. Bulk-Wrap Functions You Already Have\n\nFor Next.js Server Actions, tRPC procedures, or any plain functions:\n\n```ts\nimport { actionsFromHandlers, s } from \"@ageniti/core\";\nimport * as handlers from \"./app/actions/tasks\"; // your existing functions\n\nexport const actions = actionsFromHandlers(handlers, {\n  createTask: {\n    description: \"Create a task.\",\n    input: s.object({ title: s.string() }),\n    sideEffects: \"write\",\n  },\n  searchTasks: {\n    description: \"Search tasks.\",\n    input: s.object({ query: s.string() }),\n  },\n});\n```\n\nOr `defineActions` for full control:\n\n```ts\nimport { defineActions, s } from \"@ageniti/core\";\n\nexport const actions = defineActions({\n  createTask: {\n    description: \"Create a task.\",\n    input: s.object({ title: s.string() }),\n    run: async ({ title }) => tasks.create({ title }),\n  },\n  // function shorthand for read-only no-input actions\n  ping: () => ({ ok: true, time: Date.now() }),\n});\n```\n\nCamelCase keys are normalized to snake_case action names automatically.\n\n### 4. Streaming Events\n\nEvery action runs through a runtime that emits **live events** as it\nexecutes. UIs, agents, and log shippers can subscribe without owning the\naction:\n\n```ts\nconst events = runtime.stream(\"create_task\", { title: \"Ship v1\" });\n\nfor await (const event of events) {\n  if (event.type === \"log\") console.log(event.level, event.message);\n  if (event.type === \"progress\") updateProgressBar(event.percent);\n  if (event.type === \"artifact\") attachToUi(event.artifact);\n  if (event.type === \"result\") finalize(event.envelope);\n}\n```\n\nEvents come from `ctx.logger.*`, `ctx.progress.report()`, and\n`ctx.artifacts.add()` inside your `run()` function. The CLI's `--ndjson`\nmode and the React hook are both built on this primitive.\n\n### 5. Typed Client + Codegen\n\n```ts\nimport { createClient } from \"@ageniti/core/client\";\n\n// In-process\nconst client = createClient({ runtime });\nconst task = await client.create_task({ title: \"Hello\" });\n//      ^? { id: string; title: string }\n\n// Or talk to a remote @ageniti HTTP server\nconst remote = createClient({ url: \"https://api.example.com\" });\nconst tasks = await remote.search_tasks({ query: \"today\" });\n```\n\nRemote HTTP clients can send `metadata`, `confirm`, and `idempotencyKey`.\nTrusted `user` / `auth` must be resolved server-side via headers or\n`resolveContext`, not passed in the request body.\n\nGenerate `.d.ts` for the typed client surface from your action manifest:\n\n```ts\nimport { generateClientTypes } from \"@ageniti/core/client-gen\";\nimport { writeFile } from \"node:fs/promises\";\n\nawait writeFile(\".ageniti/client.d.ts\", generateClientTypes(actions));\n```\n\n## React\n\nTwo layers: a stateless adapter and a state-machine hook.\n\n```ts\n// app/components/CreateTaskButton.tsx\n\"use client\";\nimport { useAction } from \"@ageniti/core/react-hooks\";\nimport { runtime } from \"@/src/ageniti/app\";\nimport { createTask } from \"@/src/ageniti/actions/tasks\";\n\nexport function CreateTaskButton() {\n  const { invoke, status, data, error, logs, progress, cancel } =\n    useAction(createTask, { runtime });\n\n  return (\n    <>\n      <button onClick={() => invoke({ title: \"Hello\" })} disabled={status === \"loading\"}>\n        {status === \"loading\" ? `${progress?.percent ?? 0}%` : \"Create\"}\n      </button>\n      {status === \"loading\" && <button onClick={cancel}>Cancel</button>}\n      {status === \"success\" && <p>Created task {data.id}</p>}\n      {status === \"error\" && <p>Error: {error.message}</p>}\n      <pre>{logs.map((l) => l.message).join(\"\\n\")}</pre>\n    </>\n  );\n}\n```\n\nThe hook subscribes to `runtime.stream` so logs / artifacts / progress\nupdate live during the invocation. Unmounts auto-abort.\n\n## Exposing Surfaces\n\n```ts\nimport { createAgenitiApp, createMcpStdioServer } from \"@ageniti/core\";\nimport { actions } from \"./actions\";\n\nexport const app = createAgenitiApp({\n  name: \"tasks\",\n  actions,\n  description: \"Task management actions for operators, automation, and agent callers.\",\n});\n\n// CLI\napp.createCli().main();\n\n// MCP stdio (auto-detects Content-Length or newline framing)\ncreateMcpStdioServer({ actions: app.actions, runtime: app.runtime }).start();\n\n// HTTP (Express / Hono / Next.js Route Handler / raw Node)\nconst handler = app.createHttpHandler();\n\n// OpenAI / AI SDK tool specs\nconst openai = app.createOpenAITools();\nconst responses = app.createOpenAIResponsesTools();\nconst aiSdk = app.createAISDKTools();\nconst manifest = app.createFunctionCallingManifest();\n```\n\nEach surface is generated from the same action contract.\n\n## Runtime Capabilities\n\nThe runtime handles all the cross-cutting concerns so your `run()` function\nstays focused on business logic:\n\n- **Validation** (input, output, JSON-serializable check)\n- **Permission gating** (overridable `permissionChecker`)\n- **Confirmation gate** for destructive actions (machine surfaces require\n  `{ confirm: true }` or surface to be `react`/`dev`)\n- **Idempotency** — `idempotencyKey` replays a cached envelope scoped by\n  action, validated input, surface, and trusted caller fingerprint; LRU cap\n  keeps memory bounded\n- **Concurrency limits** per action — returns `CONCURRENCY_LIMIT` (retryable)\n- **Timeout + retry** — per-attempt `AbortController` so retries see fresh\n  signal\n- **Cancellation** — external `signal`, CLI SIGINT, React unmount all wired\n- **Streaming events** — log / progress / artifact / result\n- **Redaction** — log fields, artifact metadata, error messages (Bearer /\n  JWT / `sk-` style tokens)\n- **Hooks** — `onInvocationStart`, `onInvocationEnd` for telemetry\n- **Deprecated warnings** — emitted on every invocation of a deprecated action\n\n## The Envelope\n\nEvery invocation returns the same envelope shape:\n\n```ts\n{\n  ok: true,\n  data: { /* validated output */ },\n  artifacts: [...],\n  logs: [...],\n  meta: { action, invocationId, surface, durationMs, idempotent? },\n}\n```\n\nOr on failure:\n\n```ts\n{\n  ok: false,\n  error: { code, message, issues, retryable },\n  artifacts: [...],\n  logs: [...],\n  meta: { ... },\n}\n```\n\nStandard error codes are exported as `ERROR_CODES`:\n\n```\nACTION_NOT_FOUND, VALIDATION_ERROR, OUTPUT_VALIDATION_ERROR,\nOUTPUT_SERIALIZATION_ERROR, AUTHENTICATION_ERROR, AUTHORIZATION_ERROR,\nRATE_LIMITED, TIMEOUT, CANCELLED, CONFLICT, EXTERNAL_SERVICE_ERROR,\nINTERNAL_ERROR, UNSUPPORTED_SURFACE, UNSAFE_ACTION,\nCONFIRMATION_REQUIRED, CONCURRENCY_LIMIT\n```\n\nHTTP maps these to `400 / 401 / 403 / 404 / 405 / 409 / 413 / 415 / 429 /\n499 / 500 / 502 / 504`. CLI maps them to `0 / 1 / 2 / 3 / 4 / 5 / 124 / 130`.\n\n## Testing\n\n```ts\nimport { createTestRuntime, expectOk, expectError, collectStream } from \"@ageniti/core/test-utils\";\nimport { createTask } from \"./actions/tasks\";\n\ntest(\"create_task happy path\", async () => {\n  const t = createTestRuntime([createTask], { services: { tasks: stubTasksService } });\n  const env = await t.invoke(\"create_task\", { title: \"Hello\" });\n  const data = expectOk(env);\n  expect(data.title).toBe(\"Hello\");\n});\n\ntest(\"rejects empty title\", async () => {\n  const t = createTestRuntime([createTask]);\n  const env = await t.invoke(\"create_task\", { title: \"\" });\n  expectError(env, \"VALIDATION_ERROR\");\n});\n\ntest(\"emits progress events\", async () => {\n  const t = createTestRuntime([longRunning]);\n  const events = await collectStream(t.stream(\"long_running\", {}));\n  const progress = events.filter((e) => e.type === \"progress\");\n  expect(progress.length).toBeGreaterThan(0);\n});\n```\n\n## Drop-In Into An Existing App\n\nYou don't restructure your app. Pick the functions you want to expose,\ndeclare them as actions, mount the surfaces:\n\n```ts\n// app/actions/tasks.ts — your existing Server Actions / handlers\n\"use server\";\nexport async function createTask(input: { title: string }) { /* ... */ }\n\n// src/ageniti/app.ts — new\nimport { createAgenitiApp, actionsFromHandlers, s } from \"@ageniti/core\";\nimport * as handlers from \"@/app/actions/tasks\";\n\nexport const app = createAgenitiApp({\n  name: \"tasks\",\n  actions: actionsFromHandlers(handlers, {\n    createTask: {\n      description: \"Create a task.\",\n      input: s.object({ title: s.string() }),\n      sideEffects: \"write\",\n    },\n  }),\n});\n\n// app/api/[[...ageniti]]/route.ts\nimport { app } from \"@/src/ageniti/app\";\nconst handler = app.createHttpHandler();\nexport { handler as GET, handler as POST };\n```\n\nThat's it. The same actions are now reachable from CLI (`npx ageniti\ncreate-task --title hello`), MCP (`ageniti mcp --stdio`), HTTP (`/ageniti/...`),\nOpenAI / AI SDK tools, and the React hook.\n\n## Examples\n\n| File | Shows |\n|---|---|\n| [examples/hello.cli.js](examples/hello.cli.js) | Minimum viable action + CLI |\n| [examples/task-app.js](examples/task-app.js) | Real-world app with multiple actions |\n| [examples/demo.cli.js](examples/demo.cli.js) | Multi-surface demo app with CLI, dev, and MCP modes |\n| [examples/buildable-app.mjs](examples/buildable-app.mjs) | Minimal build-safe app export for launcher/package flows |\n| [examples/streaming.js](examples/streaming.js) | Live progress / log streaming |\n| [examples/zod-action.js](examples/zod-action.js) | Using Zod-style schemas |\n| [examples/typed-client.js](examples/typed-client.js) | Typed in-process client, raw envelopes, streams, and client codegen |\n| [examples/bulk-handlers.js](examples/bulk-handlers.js) | `defineActions` / `actionsFromHandlers` |\n| [examples/test-helpers.test.js](examples/test-helpers.test.js) | Testing actions |\n| [examples/openai-responses-host.js](examples/openai-responses-host.js) | OpenAI Responses tool spec |\n| [examples/ai-sdk-route.js](examples/ai-sdk-route.js) | Vercel AI SDK tool integration |\n| [examples/http-gateway.js](examples/http-gateway.js) | HTTP server with detailed status codes |\n| [examples/mcp-host.js](examples/mcp-host.js) | MCP host calling actions |\n\n## Documentation\n\n- [Getting Started](docs/getting-started.md)\n- [API Reference](docs/api.md)\n- [Scope](docs/scope.md)\n- [Skill Spec](docs/skill.md)\n- [Release Checklist](docs/release-checklist.md)\n\n## Contributing\n\nPRs and issues welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","readmeFilename":"README.md"}