[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81193":3},{"id":4,"name":5,"fullName":6,"owner":5,"repo":5,"description":7,"homepage":8,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":14,"stars7d":15,"stars30d":15,"stars90d":14,"forks30d":14,"starsTrendScore":14,"compositeScore":16,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":33,"readmeContent":34,"aiSummary":35,"trendingCount":14,"starSnapshotCount":14,"syncStatus":15,"lastSyncTime":36,"discoverSource":37},81193,"Ageniti","Ageniti\u002FAgeniti","A standard SDK for building agent-facing apps across MCP, CLI, React, and AI tool stacks.","https:\u002F\u002Fageniti.dev\u002F",null,"JavaScript",29,1,27,0,2,42.1,"MIT License",false,"main",true,[22,23,24,25,26,27,28,29,30,31,32],"agent","agents","app","cli","cli-app","developer-tools","mcp","mcp-server","sdk","sdk-js","typescript","2026-06-12 04:01:32","\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fageniti.dev\">\n    \u003Cimg src=\"assets\u002Flogo.svg\" alt=\"Ageniti logo\" width=\"96\" height=\"96\">\n  \u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Ch1 align=\"center\">Ageniti\u003C\u002Fh1>\n\n\u003Cp align=\"center\">\n  \u003Cstrong>The action primitive for apps that need to be callable by agents.\u003C\u002Fstrong>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@ageniti\u002Fcore\">\u003Cimg alt=\"npm version\" src=\"https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fv\u002F@ageniti\u002Fcore?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@ageniti\u002Fcore\">\u003Cimg alt=\"npm downloads\" src=\"https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fdm\u002F@ageniti\u002Fcore?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FAgeniti\u002Fageniti\u002Fblob\u002Fmain\u002FLICENSE\">\u003Cimg alt=\"license\" src=\"https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fl\u002F@ageniti\u002Fcore?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@ageniti\u002Fcore\">\u003Cimg alt=\"node\" src=\"https:\u002F\u002Fimg.shields.io\u002Fnode\u002Fv\u002F@ageniti\u002Fcore?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FAgeniti\u002Fageniti\">\u003Cimg alt=\"module format\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fmodule-ESM-black?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FcmkxR7GcYu\">\u003Cimg alt=\"discord\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDiscord-Join-5865F2?style=flat-square&logo=discord&logoColor=white\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fageniti.dev\">Website\u003C\u002Fa>\n  ·\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FAgeniti\u002Fageniti\">GitHub\u003C\u002Fa>\n  ·\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@ageniti\u002Fcore\">npm\u003C\u002Fa>\n  ·\n  \u003Ca href=\"docs\u002Fgetting-started.md\">Getting Started\u003C\u002Fa>\n  ·\n  \u003Ca href=\"docs\u002Fapi.md\">API\u003C\u002Fa>\n\u003C\u002Fp>\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 \u002F 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> **Stability — pre-1.0.** Ageniti is currently `0.x`. The action contract and\n> primary surfaces (CLI, HTTP, MCP, AI SDK) are stable enough for real use, but\n> minor versions may still introduce breaking changes to export shape, adapter\n> APIs, or manifest format until `1.0`. Pin an exact version (`@ageniti\u002Fcore@0.1.x`)\n> in production and read the [CHANGELOG](.\u002FCHANGELOG.md) before upgrading.\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\u002Fcore\n```\n\nSubpath exports:\n\n| Subpath | What it gives you |\n|---|---|\n| `@ageniti\u002Fcore` | Main authoring API plus packaging\u002Fproject helpers such as `buildArtifacts`, `packageArtifacts`, `publishArtifacts`, `createGuideDoc`, `exportDocs`, `initProject`, `doctorProject`, and `detectTypeScriptRuntime` |\n| `@ageniti\u002Fcore\u002Fai-sdk` | `createOpenAITools`, `createOpenAIResponsesTools`, `createAISDKTools`, `createFunctionCallingManifest` |\n| `@ageniti\u002Fcore\u002Fadapters` | Built-in surface adapters and helpers such as `httpAdapter`, `mcpAdapter`, `aiSdkAdapter`, `cliAdapter`, `jsonAdapter`, `reactAdapter`, `devAdapter`, `defaultSurfaceAdapters`, `defineSurfaceAdapter`, and `findAdapter` |\n| `@ageniti\u002Fcore\u002Fapp`, `\u002Fcore`, `\u002Fcli`, `\u002Fmcp`, `\u002Fdev`, `\u002Fmanifest`, `\u002Fjson-runner`, `\u002Flint` | Narrow imports for the corresponding runtime or surface modules |\n| `@ageniti\u002Fcore\u002Fhttp` | `createHttpHandler`, `createHttpServer`, `parseRequestBody`, `sendJson`, `sendText` |\n| `@ageniti\u002Fcore\u002Fhandlers` | `defineActions`, `actionFromHandler`, `actionsFromHandlers` |\n| `@ageniti\u002Fcore\u002Fschema-adapter` | `wrapSchema`, Zod \u002F Standard Schema v1 interop |\n| `@ageniti\u002Fcore\u002Fschema` | Schema helpers only |\n| `@ageniti\u002Fcore\u002Fclient` | `createClient`, `AgenitiClientError` |\n| `@ageniti\u002Fcore\u002Fclient-gen` | `generateClientTypes`, `jsonSchemaToTs` |\n| `@ageniti\u002Fcore\u002Ftest-utils` | `createTestRuntime`, `expectOk`, `expectError`, `expectLog`, `collectStream`, `stubAction` |\n| `@ageniti\u002Fcore\u002Freact` | `createReactActionAdapter`, `makeInvoker`, `streamAction` (no React import) |\n| `@ageniti\u002Fcore\u002Freact-hooks` | `useAction` — full state-machine hook (React peer dep) |\n| `@ageniti\u002Fcore\u002Fpackage.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\u002Fcore\";\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\u002Fcore\";\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` \u002F `.parse` \u002F\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\u002Fcore\";\nimport * as handlers from \".\u002Fapp\u002Factions\u002Ftasks\"; \u002F\u002F 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\u002Fcore\";\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  \u002F\u002F 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\u002Fcore\u002Fclient\";\n\n\u002F\u002F In-process\nconst client = createClient({ runtime });\nconst task = await client.create_task({ title: \"Hello\" });\n\u002F\u002F      ^? { id: string; title: string }\n\n\u002F\u002F Or talk to a remote @ageniti HTTP server\nconst remote = createClient({ url: \"https:\u002F\u002Fapi.example.com\" });\nconst tasks = await remote.search_tasks({ query: \"today\" });\n```\n\nRemote HTTP clients can send `metadata`, `confirm`, and `idempotencyKey`.\nTrusted `user` \u002F `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\u002Fcore\u002Fclient-gen\";\nimport { writeFile } from \"node:fs\u002Fpromises\";\n\nawait writeFile(\".ageniti\u002Fclient.d.ts\", generateClientTypes(actions));\n```\n\n## React\n\nTwo layers: a stateless adapter and a state-machine hook.\n\n```ts\n\u002F\u002F app\u002Fcomponents\u002FCreateTaskButton.tsx\n\"use client\";\nimport { useAction } from \"@ageniti\u002Fcore\u002Freact-hooks\";\nimport { runtime } from \"@\u002Fsrc\u002Fageniti\u002Fapp\";\nimport { createTask } from \"@\u002Fsrc\u002Fageniti\u002Factions\u002Ftasks\";\n\nexport function CreateTaskButton() {\n  const { invoke, status, data, error, logs, progress, cancel } =\n    useAction(createTask, { runtime });\n\n  return (\n    \u003C>\n      \u003Cbutton onClick={() => invoke({ title: \"Hello\" })} disabled={status === \"loading\"}>\n        {status === \"loading\" ? `${progress?.percent ?? 0}%` : \"Create\"}\n      \u003C\u002Fbutton>\n      {status === \"loading\" && \u003Cbutton onClick={cancel}>Cancel\u003C\u002Fbutton>}\n      {status === \"success\" && \u003Cp>Created task {data.id}\u003C\u002Fp>}\n      {status === \"error\" && \u003Cp>Error: {error.message}\u003C\u002Fp>}\n      \u003Cpre>{logs.map((l) => l.message).join(\"\\n\")}\u003C\u002Fpre>\n    \u003C\u002F>\n  );\n}\n```\n\nThe hook subscribes to `runtime.stream` so logs \u002F artifacts \u002F progress\nupdate live during the invocation. Unmounts auto-abort.\n\n## Exposing Surfaces\n\n```ts\nimport { createAgenitiApp, createMcpStdioServer } from \"@ageniti\u002Fcore\";\nimport { actions } from \".\u002Factions\";\n\nexport const app = createAgenitiApp({\n  name: \"tasks\",\n  actions,\n  description: \"Task management actions for operators, automation, and agent callers.\",\n});\n\n\u002F\u002F CLI\napp.createCli().main();\n\n\u002F\u002F MCP stdio (auto-detects Content-Length or newline framing)\ncreateMcpStdioServer({ actions: app.actions, runtime: app.runtime }).start();\n\n\u002F\u002F HTTP (Express \u002F Hono \u002F Next.js Route Handler \u002F raw Node)\nconst handler = app.createHttpHandler();\n\n\u002F\u002F OpenAI \u002F 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`\u002F`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 \u002F progress \u002F artifact \u002F result\n- **Redaction** — log fields, artifact metadata, error messages (Bearer \u002F\n  JWT \u002F `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: { \u002F* validated output *\u002F },\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 \u002F 401 \u002F 403 \u002F 404 \u002F 405 \u002F 409 \u002F 413 \u002F 415 \u002F 429 \u002F\n499 \u002F 500 \u002F 502 \u002F 504`. CLI maps them to `0 \u002F 1 \u002F 2 \u002F 3 \u002F 4 \u002F 5 \u002F 124 \u002F 130`.\n\n## Testing\n\n```ts\nimport { createTestRuntime, expectOk, expectError, collectStream } from \"@ageniti\u002Fcore\u002Ftest-utils\";\nimport { createTask } from \".\u002Factions\u002Ftasks\";\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\u002F\u002F app\u002Factions\u002Ftasks.ts — your existing Server Actions \u002F handlers\n\"use server\";\nexport async function createTask(input: { title: string }) { \u002F* ... *\u002F }\n\n\u002F\u002F src\u002Fageniti\u002Fapp.ts — new\nimport { createAgenitiApp, actionsFromHandlers, s } from \"@ageniti\u002Fcore\";\nimport * as handlers from \"@\u002Fapp\u002Factions\u002Ftasks\";\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\u002F\u002F app\u002Fapi\u002F[[...ageniti]]\u002Froute.ts\nimport { app } from \"@\u002Fsrc\u002Fageniti\u002Fapp\";\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 (`\u002Fageniti\u002F...`),\nOpenAI \u002F AI SDK tools, and the React hook.\n\n## Examples\n\n| File | Shows |\n|---|---|\n| [examples\u002Fhello.cli.js](examples\u002Fhello.cli.js) | Minimum viable action + CLI |\n| [examples\u002Ftask-app.js](examples\u002Ftask-app.js) | Real-world app with multiple actions |\n| [examples\u002Fdemo.cli.js](examples\u002Fdemo.cli.js) | Multi-surface demo app with CLI, dev, and MCP modes |\n| [examples\u002Fbuildable-app.mjs](examples\u002Fbuildable-app.mjs) | Minimal build-safe app export for launcher\u002Fpackage flows |\n| [examples\u002Fstreaming.js](examples\u002Fstreaming.js) | Live progress \u002F log streaming |\n| [examples\u002Fzod-action.js](examples\u002Fzod-action.js) | Using Zod-style schemas |\n| [examples\u002Ftyped-client.js](examples\u002Ftyped-client.js) | Typed in-process client, raw envelopes, streams, and client codegen |\n| [examples\u002Fbulk-handlers.js](examples\u002Fbulk-handlers.js) | `defineActions` \u002F `actionsFromHandlers` |\n| [examples\u002Ftest-helpers.test.js](examples\u002Ftest-helpers.test.js) | Testing actions |\n| [examples\u002Fopenai-responses-host.js](examples\u002Fopenai-responses-host.js) | OpenAI Responses tool spec |\n| [examples\u002Fai-sdk-route.js](examples\u002Fai-sdk-route.js) | Vercel AI SDK tool integration |\n| [examples\u002Fhttp-gateway.js](examples\u002Fhttp-gateway.js) | HTTP server with detailed status codes |\n| [examples\u002Fmcp-host.js](examples\u002Fmcp-host.js) | MCP host calling actions |\n\n## Documentation\n\n- [Getting Started](docs\u002Fgetting-started.md)\n- [API Reference](docs\u002Fapi.md)\n- [Scope](docs\u002Fscope.md)\n- [Skill Spec](docs\u002Fskill.md)\n- [Release Checklist](docs\u002Frelease-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","Ageniti 是一个用于构建面向代理的应用的标准SDK，支持MCP、CLI、React以及AI工具栈。其核心功能在于定义一次操作（包括输入输出协议、副作用、权限等），即可通过统一的运行时被多种调用方（如CLI、HTTP、MCP、OpenAI\u002FAI SDK工具、React UI）以相同的方式调用，确保了流事件、数据脱敏及错误处理的一致性。该项目采用JavaScript编写，并遵循MIT许可协议。它适用于需要为自动化系统或外部工具提供可调用接口的应用场景，简化了跨平台交互中的复杂性，提高了开发效率和一致性。目前处于0.x版本阶段，在1.0正式版前可能会有不兼容的小改动。","2026-06-11 04:03:50","CREATED_QUERY"]