# OrchaJS > OrchaJS is an open-source, filesystem-first JavaScript and TypeScript framework for building durable AI agents inside existing applications. Website: https://orcha.sh Source: https://github.com/amarsia/orcha npm: https://www.npmjs.com/package/orchajs License: MIT An agent is a folder. Orcha treats that folder as the complete, portable source of truth. Files define the model, instructions, actions, skills, tests, and evaluations. There is no proprietary orchestration graph, no hosted control plane, and no export step. It is a library, not a platform. It runs anywhere JavaScript runs: Node.js, React, React Native, Next.js, Express, NestJS, and other JavaScript or TypeScript applications. Add it the way you would add Prisma or Zod. ## Who it is for - Node.js, React, and other JavaScript or TypeScript teams who want AI agents inside the applications they already ship. - Product and platform engineers who need pause, resume, human-in-the-loop, tests, and evaluations without a separate agent runtime. - Teams who want agent behavior versioned in git as ordinary files, not locked inside someone else's dashboard. ## What it is OrchaJS compiles filesystem-based agent definitions into a typed runtime. After `orcha.init()`, registered agents are called as `orcha.supportBot.run(...)`. Durable sessions persist automatically. The same source runs locally and in production. The npm package is `orchajs`. Import the runtime singleton as `{ orcha }`. Do not invent path-based runtime APIs. ## What it supports - Durable sessions: `.run()`, `.resume()`, `.get()`, `.history()`, `.list()`, `.update()`, `.pause()`, and `.events()`. - Local actions: any trusted Node.js code — APIs, databases, SDKs, third-party services. - Client actions: pause for the calling app, UI, or a human, then resume with tool results. - Skills: specialized procedures loaded only when relevant. - Subagents: parent agents that delegate to private specialists with their own sessions. - Tests: real-model contract tests with optional mocked actions. - Evaluations: asynchronous model judges with metrics and thresholds. - Multimodal input: local files and remote media. - Sandboxed or native local action execution. - Production builds through the application's existing `npm run build`. ## Model providers OpenAI, Anthropic, DeepSeek, Google Gemini (`googlegenai`), Google Vertex AI, and Amazon Bedrock. ## Quickstart Add Orcha to an existing project: ```sh npm install orchajs npx orcha init ``` Or create a new project: ```sh npx create-orcha@latest my-app-name ``` Give a coding agent the Orcha development guide: ```sh npx skills add Amarsia/orcha ``` ```ts import "./orcha/index.js"; import { orcha } from "orchajs"; const result = await orcha.exampleAgent.run( "Help me with my order.", ).result; ``` ## Agent structure ```text orcha/ index.ts supportBot/ index.json instructions.md actions/ skills/ tests/ evaluations/ ``` - `orcha/index.ts` initializes providers and registers agents. - An agent's `index.json` selects provider, model, limits, and text or JSON output. - `instructions.md` contains the agent's stable role and operating boundaries. - Actions are typed local or client-owned tools defined with JSON Schema. - Skills are lazy-loaded procedural instructions. - Tests run real agent scenarios with optional mocked actions. - Evaluations are asynchronous LLM judges with explicit metrics and thresholds. - Durable sessions can be resumed by session ID and can pause for client actions or humans. # Documentation # Getting Started Install OrchaJS in an existing Node.js app or create a new project with create-orcha. Source: https://orcha.sh/docs Markdown: https://orcha.sh/docs.mdx ## Prerequisites Requires Node.js 20.12 or newer and an API key for the model provider of your choice. ## Add Orcha to an existing project ```bash npm install orchajs npx orcha init ``` Running `orcha init` in the current directory: - Creates `orcha/exampleAgent/index.json` - Creates `orcha/exampleAgent/instructions.md` - Creates `orcha/index.ts` with Anthropic configured and `exampleAgent` registered - Creates root-level `AGENTS.md` with the complete Orcha development guide - Adds `.orcha/` to `.gitignore` Existing files are skipped, not overwritten. ## Add Orcha as a skill Give your coding agent the complete Orcha development guide: ```bash npx skills add Amarsia/orcha ``` ## Create a new Node.js project ```bash npx create-orcha@latest my-app-name cd my-app-name npm install cp .env.example .env ``` The starter includes example agents and scripts for the local development playground, tests, and production compilation. ## Add your provider credentials Create a root-level `.env` file and add the credentials for the provider configured in `orcha/index.ts`. ### Anthropic ```bash ANTHROPIC_API_KEY=your-anthropic-key ``` ### OpenAI ```bash OPENAI_API_KEY=your-openai-key ``` ### DeepSeek ```bash DEEPSEEK_API_KEY=your-deepseek-key ``` ### Google Gemini ```bash GOOGLE_API_KEY=your-google-ai-key ``` The provider name in agent configuration is `googlegenai`. ### Google Vertex AI ```bash GOOGLE_CLOUD_PROJECT=your-project-id GOOGLE_CLOUD_LOCATION=us-central1 GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json ``` Vertex AI can also use Application Default Credentials without `GOOGLE_APPLICATION_CREDENTIALS`. ### Amazon Bedrock ```bash AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=your-access-key-id AWS_SECRET_ACCESS_KEY=your-secret-access-key AWS_SESSION_TOKEN=your-session-token ``` Bedrock uses the normal AWS credential chain when explicit credentials are omitted. [Read more about model providers →](/docs/model-providers) --- # Create your first agent Create your first OrchaJS agent, call .run(), and read the result, stream, and session ID. Source: https://orcha.sh/docs/first-agent Markdown: https://orcha.sh/docs/first-agent.mdx An agent is a folder with model configuration and instructions. ```text orcha/ index.ts exampleAgent/ index.json instructions.md ``` If you ran `npx orcha init`, these files already exist. ## Configure the agent `orcha/exampleAgent/index.json`: ```json { "name": "Example Agent", "description": "Answer general questions clearly and concisely.", "provider": "anthropic", "model": "claude-sonnet-4-6", "region": "provider_managed", "maxTokens": 10240, "outputType": "text" } ``` ## Write its instructions `orcha/exampleAgent/instructions.md`: ```md You are a concise and helpful assistant. Answer the user's question directly before adding supporting detail. Use clear language and practical examples. Ask one focused question when the request is ambiguous. Separate established facts from assumptions. If you are uncertain, say so instead of inventing an answer. ``` ## Register it `orcha/index.ts`: ```ts orcha.init({ providers: { anthropic: process.env.ANTHROPIC_API_KEY ?? "", }, agents: { exampleAgent: "./exampleAgent", }, }); ``` The registration key becomes the runtime property `orcha.exampleAgent`. ## Run it from code ```ts const agent = orcha.exampleAgent; const execution = agent.run("What is an idempotent API?"); const result = await execution.result; if (result.status === "completed") { console.log(result.output); } ``` Every call to `run()` creates a new durable session. ## Input reference `run()` accepts a string or an input object. ### Text ```ts agent.run("Explain durable sessions."); ``` The equivalent text block is: ```ts agent.run({ content: { type: "text", text: "Explain durable sessions.", }, }); ``` ### Local file ```ts agent.run({ content: [ { type: "text", text: "Summarize this document." }, { filePath: "./documents/report.pdf" }, ], }); ``` `type: "file"` is optional when `filePath` is present. Relative paths resolve from the Orcha project root. `mimeType` is inferred from the file extension when possible, or can be provided: ```ts { type: "file", filePath: "./documents/report.bin", mimeType: "application/pdf", } ``` ### Remote URL ```ts agent.run({ content: [ { type: "text", text: "Describe this image." }, { url: "https://cdn.example.com/photo.jpg", mimeType: "image/jpeg", }, ], }); ``` `type: "url"` is optional when `url` is present. Use `url` for any remote image, document, audio, or video. `mimeType` tells Orcha what the resource contains. Actual media support depends on the selected provider and model. ### Additional input fields ```ts agent.run({ content: "Help with account acct_123.", name: "Account support", metadata: { accountId: "acct_123", }, variables: { companyName: "Acme", }, clientCapabilities: [ "request_human_approval", ], }); ``` - `name` is an optional session label. - `metadata` stores durable application context. - `variables` replace `{{ variableName }}` placeholders in instructions. - `clientCapabilities` lists client actions available to this caller. ## What `run()` returns `run()` returns an execution handle immediately: ```ts const { sessionId, stream, result, snapshot, evaluations, } = agent.run("Hello"); ``` - `sessionId` is available immediately. - `stream` is a `ReadableStream` of cumulative execution snapshots. - `result` is a promise for the final run result. - `snapshot` is the latest snapshot, or `undefined` before the first update. - `evaluations` is a promise for asynchronous evaluation results. Await `result` first. On the resolved run result, `result.output` is the agent's final output, as shown below. ### Text output For an agent configured with `"outputType": "text"`, `result.output` is a string: ```ts const result = await execution.result; if (result.status === "completed") { console.log(result.output); // string } ``` ### JSON output For an agent configured with `"outputType": "json"`, `result.output` is the object defined by the agent's `outputSchema`: ```ts const result = await execution.result; if (result.status === "completed") { console.log(result.output); // validated JSON object } ``` Text and JSON use the same `result.output` property. The difference comes from the agent configuration, not from a different execution field. ### Result states ```ts const result = await execution.result; ``` `result.status` is one of: - `completed` — contains `output` and optional usage. - `waiting_for_client_action` — contains `clientToolCalls`. - `paused` — the execution stopped and can be resumed. - `failed` — contains a structured `error`. Every result includes `sessionId`. Save it when the conversation may continue later with `agent.resume(sessionId, ...)`. [Read the complete multimodal reference →](/docs/multimodal) --- # Dev playground Open the OrchaJS local playground with npx orcha playground to run and inspect agents. Source: https://orcha.sh/docs/dev-playground Markdown: https://orcha.sh/docs/dev-playground.mdx From your application directory, run: ```bash npx orcha playground ``` Orcha opens the local development playground in your browser. --- # Folder Structure The OrchaJS folder layout for agents, actions, skills, tests, and the registry. Source: https://orcha.sh/docs/folder-structure Markdown: https://orcha.sh/docs/folder-structure.mdx The `orcha/` directory is the source of truth. Placement determines behavior, so an agent remains understandable by opening its folder. ```text orcha/ index.ts supportAgent/ index.json instructions.md actions/ lookupOrder/ index.json index.js skills/ delayedOrderHandling/ index.json instructions.md tests/ delayedOrder/ index.json evaluations/ supportQuality/ index.json ``` ## `orcha/index.ts` Initializes providers and explicitly registers agents: ```ts orcha.init({ providers: { openai: process.env.OPENAI_API_KEY ?? "", }, agents: { supportAgent: "./supportAgent", }, }); ``` Only registered agents are compiled. The registration key becomes the runtime property: `orcha.supportAgent`. ## Agent files ### `agent/index.json` Chooses the provider, model, output type, and model limits. `name`, `provider`, and `model` are required. ```json { "name": "Support Agent", "description": "Resolves order questions using confirmed order data.", "provider": "openai", "model": "gpt-5-mini", "maxTokens": 4000, "outputType": "text" } ``` ### `agent/instructions.md` Contains stable behavior: role, boundaries, decision rules, and guidance for tools. Keep changing user input out of this file and pass it to `run()` instead. ```md You help customers understand their orders. Always look up an order before making claims about its status. Never invent order data. ``` Prompt variables use `{{ variableName }}` and are supplied once when the session is created. ## `actions/` Actions let the model do work. Every direct child folder has metadata in `index.json`. Local actions also have executable `index.js`. ```text actions/ lookupOrder/ index.json index.js ``` - Omit `execution` for a local action. - Use `"execution": "client"` when the caller must do the work. - Direct child folders are discovered automatically. ## `skills/` Skills are procedures loaded only when relevant: ```text skills/ delayedOrderHandling/ index.json instructions.md ``` `index.json` is the small discovery card. `instructions.md` is the full procedure. Orcha initially exposes only the card, keeping the base prompt small. ## `tests/` Each direct child is one model-backed contract test: ```text tests/ delayedOrder/ index.json ``` The test defines an input, action mocks, and deterministic expectations. The folder name is its CLI selector: `orcha test supportAgent/delayedOrder`. ## `evaluations/` Each direct child configures an asynchronous model judge: ```text evaluations/ supportQuality/ index.json ``` Evaluations score qualities such as grounding or clarity. Tests check deterministic contracts; evaluations check probabilistic quality. ## Generated `.orcha/` `.orcha/` is generated output, not source: ```text .orcha/ dist/ bundle.js sessions/ supportAgent/ ses_...jsonl .build/ .cli/ ``` `dist/` is the production agent bundle. `.build/` and `.cli/` are temporary compiler artifacts. Do not edit or commit any of them. Access sessions through `agent.get()`, `history()`, `events()`, and `list()` rather than reading storage files directly. ## Discovery rules - Agents and subagents must be registered in `orcha/index.ts`. - Actions, skills, tests, and evaluations are discovered from direct child folders. - Set `"enabled": false` in an item's `index.json` to keep work in progress inactive. - Enabled entries must contain their required files. - Model-facing names must be unique within an agent. - Invalid files and schemas fail during `orcha dev` or `orcha build`, before a user run. --- # Model Providers Configure OrchaJS with OpenAI, Anthropic, DeepSeek, Gemini, Vertex AI, or Amazon Bedrock. Source: https://orcha.sh/docs/model-providers Markdown: https://orcha.sh/docs/model-providers.mdx Configure providers once in `orcha/index.ts`, then select one in each agent's `index.json`. ## API-key providers OpenAI, Anthropic, DeepSeek, and Google GenAI accept an API key string: ```ts orcha.init({ providers: { openai: process.env.OPENAI_API_KEY ?? "", anthropic: process.env.ANTHROPIC_API_KEY ?? "", deepseek: process.env.DEEPSEEK_API_KEY ?? "", googlegenai: process.env.GOOGLE_API_KEY ?? "", }, agents: { assistant: "./assistant", }, }); ``` Use an object when you need a custom endpoint: ```ts providers: { openai: { apiKey: process.env.OPENAI_API_KEY ?? "", baseUrl: "https://api.openai.com/v1", }, } ``` ## Google Vertex AI ```ts providers: { vertexai: { project: process.env.GOOGLE_CLOUD_PROJECT ?? "", location: process.env.GOOGLE_CLOUD_LOCATION ?? "us-central1", }, } ``` When `credentials` is omitted, the Google SDK uses Application Default Credentials. For an explicit service account: ```ts providers: { vertexai: { project: process.env.GOOGLE_CLOUD_PROJECT ?? "", location: process.env.GOOGLE_CLOUD_LOCATION ?? "us-central1", credentials: { clientEmail: process.env.GOOGLE_CLIENT_EMAIL ?? "", privateKey: process.env.GOOGLE_PRIVATE_KEY ?? "", }, }, } ``` ## Amazon Bedrock ```ts providers: { bedrock: { region: process.env.AWS_REGION ?? "us-east-1", }, } ``` When `credentials` is omitted, the AWS SDK uses its normal credential chain. Explicit credentials are also supported: ```ts providers: { bedrock: { region: process.env.AWS_REGION ?? "us-east-1", credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? "", secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? "", sessionToken: process.env.AWS_SESSION_TOKEN, }, }, } ``` ## Select a provider and model In the agent's `index.json`: ```json { "name": "Assistant", "provider": "openai", "model": "gpt-5-mini", "outputType": "text" } ``` `model` is the exact provider model identifier. Orcha does not rename models or translate `reasoningLevel` values between providers. Different agents and evaluations may use different configured providers: ```text assistant → OpenAI policyReviewer → Anthropic qualityJudge → Google Gemini ``` ## Environment variables The Orcha library reads the host application's existing `process.env`. Standalone CLI commands also load `.env` from the project root without overriding variables already present. ```bash OPENAI_API_KEY=... ANTHROPIC_API_KEY=... DEEPSEEK_API_KEY=... GOOGLE_API_KEY=... ``` Never place credentials in agent JSON, instructions, run metadata, prompt variables, tests, or session logs. ## Provider capabilities Text is broadly supported. Structured output, reasoning controls, multimodal input, caching, and replay behavior vary by provider and model. Orcha normalizes supported behavior and returns a clear capability error instead of silently dropping unsupported input. --- # Basic agent Example of the simplest OrchaJS text chat agent with configuration and instructions. Source: https://orcha.sh/docs/tutorial/basic-agent Markdown: https://orcha.sh/docs/tutorial/basic-agent.mdx ## The simplest text chat agent The project above is an example of the simplest text chat agent you can build with Orcha. It has a model configuration, instructions, one registry entry, and ordinary application code that runs it. It can answer order-support questions from its instructions, but it cannot look up real order data yet. Its instructions therefore prevent it from inventing order details. The next tutorials add skills, actions, client actions, and subagents to this same project. Select any file in the editor to inspect the complete example. ## Understand each file Next: [add a skill](/docs/tutorial/skills). --- # Agent with skills Example OrchaJS agent that loads specialized skill instructions only when they are relevant. Source: https://orcha.sh/docs/tutorial/skills Markdown: https://orcha.sh/docs/tutorial/skills.mdx ## Focused knowledge, loaded on demand This example is a complete technical writing agent with one skill for explaining engineering concepts. The base agent stays small. It initially sees only the skill's name, description, and triggers. When a request matches, the model loads the full procedure through Orcha's internal `load_skill` tool. Orcha continues the same run automatically, and the loaded instructions remain active for the durable session. A skill is the right fit for policy, process, domain knowledge, or a repeatable method. It guides the model but does not execute code. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [build an agent that takes action](/docs/tutorial/actions). --- # Agent that takes action Example OrchaJS agent that calls APIs, databases, or any Node.js code as a local action. Source: https://orcha.sh/docs/tutorial/actions Markdown: https://orcha.sh/docs/tutorial/actions.mdx ## Let the agent do real work This example is a complete order agent with one action: `lookup_order`. The model receives a typed tool definition, chooses when to call it, and supplies arguments that match the configured JSON Schema. The action's `index.js` is ordinary application code. It can contain any trusted Node.js logic: query your database, call an internal API, use an npm package, invoke a third-party SDK, read from a service, or perform a calculation. The in-memory order lookup here keeps the example runnable. Orcha validates the model arguments, runs `index.js`, validates its return value, gives that result back to the model, and continues until the agent produces its final answer. Your application does not need to manage that tool loop. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [put a human in the loop](/docs/tutorial/client-actions). --- # Human in the loop Example OrchaJS human-in-the-loop agent that pauses for approval, then resumes. Source: https://orcha.sh/docs/tutorial/client-actions Markdown: https://orcha.sh/docs/tutorial/client-actions.mdx ## Move work into the caller This example is a complete purchase approval agent. It can prepare the request, but it cannot approve a purchase itself. The `request_human_approval` action has `execution: "client"`, so Orcha describes the action to the model without providing executable server code. When the model requests approval, Orcha stores the request and pauses safely. The application receives the action name, validated arguments, and a `callId`. After the human decides, the application resumes that same session with the result. The process can restart or the decision can happen much later; the model context is already durable. Human approval is only one client-action pattern. The same boundary can ask a browser to upload a document, request a device location, open a confirmation screen, collect a signature, or use any capability owned by the caller. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [compose agents with subagents](/docs/tutorial/subagents). --- # Agent with subagents Example OrchaJS parent agent that delegates work to private subagents. Source: https://orcha.sh/docs/tutorial/subagents Markdown: https://orcha.sh/docs/tutorial/subagents.mdx ## Delegate focused reasoning This example is a complete research coordinator with one private subagent. The coordinator decides what to delegate, the researcher handles one focused question, and the coordinator remains responsible for the final response. A subagent is an ordinary agent folder with its own model configuration, instructions, context, and durable session. Registering it inside `coordinator.subagents` gives the parent internal tools to run, resume, and inspect that child without exposing the child as a top-level application API. The parent waits while the child runs, receives the child response as a tool result, and continues automatically. Parent and child histories remain separate and linked for inspection. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [test an agent](/docs/tutorial/tests). --- # Test an agent Write OrchaJS agent tests with real model calls, mocked actions, and contract assertions. Source: https://orcha.sh/docs/tutorial/tests Markdown: https://orcha.sh/docs/tutorial/tests.mdx ## Protect the behavior that matters This example is a complete order agent with one model-backed contract test. The test runs the real compiled agent and provider while returning a fixed response for `lookup_order`. Mocking the action makes the data deterministic without replacing the model. The expectations verify that the agent completed, called the correct action with the exact order ID, and included confirmed facts in its response. Each direct folder under `tests/` is one case. Run this case with: ```bash npx orcha test orderAgent/delayedOrder ``` Unmocked local actions execute live, so mock operations that should not touch real services during a test. Client actions must always be mocked. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [evaluate an agent](/docs/tutorial/evaluations). --- # Evaluate an agent Add OrchaJS evaluations that score completed agent responses with a model judge. Source: https://orcha.sh/docs/tutorial/evaluations Markdown: https://orcha.sh/docs/tutorial/evaluations.mdx ## Measure quality, not exact wording This example is a complete writing agent with an asynchronous model judge. The agent answers with Anthropic, while the `response_quality` evaluation uses OpenAI to score clarity and calibration independently. Evaluations are for qualities that cannot be captured reliably by substring or exact-value assertions. Every metric has a concrete criterion and an inclusive threshold from 0 to 1. Judging starts after a run completes. `execution.result` becomes available without waiting, while `execution.evaluations` resolves when every enabled judge has finished and its result has been stored. Select any file in the editor to inspect the complete standalone project. ## Understand each file Next: [deploy an agent](/docs/tutorial/production). --- # Deploy to production Deploy OrchaJS agents with your existing npm run build and production environment keys. Source: https://orcha.sh/docs/tutorial/production Markdown: https://orcha.sh/docs/tutorial/production.mdx Your production workflow does not need a separate Orcha build configuration. Use the build command your project already uses: ```bash npm run build ``` Orcha is compiled and included as part of the application build. The same agent folders and runtime API you used locally are used in production. ## Configure production credentials Provide model-provider credentials through your deployment environment: ```bash ANTHROPIC_API_KEY=... ``` Do not copy a local `.env` file into the production bundle. ## Deploy the application Deploy the output of `npm run build` the same way you deploy the rest of your Node.js application. No playground frontend is included in the production output. Application code remains unchanged: ```ts const result = await orcha.assistant.run( "Explain durable sessions.", ).result; ``` ## Preserve durable sessions The default Node storage writes sessions under `.orcha/sessions`. Use persistent shared storage when a session must: - survive a process or container restart, - resume on another application instance, - wait for a client action and continue later. Read sessions through `get()`, `history()`, `events()`, and `list()` rather than accessing storage files directly. ## Production checklist - Run `npm run build` in CI. - Run focused agent tests before deployment. - Supply provider credentials through the production environment. - Keep `.orcha/sessions` on persistent storage when sessions must resume. - Save `sessionId` in your application database when users may return later. - Await `execution.evaluations` in short-lived jobs when scores must finish before the process exits. --- # Start a session Start an OrchaJS durable session with agent.run() and read sessionId, stream, and result. Source: https://orcha.sh/docs/sessions/start Markdown: https://orcha.sh/docs/sessions/start.mdx Every `.run()` starts a new durable session. Orcha saves its messages, tool calls, results, and usage automatically. ```ts const run = orcha.supportAgent.run("Help me resolve order ord_1001."); const result = await run.result; if (result.status === "completed") { console.log(result.output); } ``` Save `run.sessionId` when the user may continue this conversation later. ## Add session details Use the object form to name a session or attach application data: ```ts const run = orcha.supportAgent.run({ content: "Help me resolve order ord_1001.", name: "Order ord_1001", metadata: { customerId: "cus_123", priority: "high", }, }); ``` `name` makes the session recognizable in your UI. `metadata` lets your application associate it with users, orders, workspaces, or other records. ## Read everything run returns `.run()` returns an execution immediately. The model continues working in the background. ```ts title="Destructure the execution" const { sessionId, stream, snapshot, result, evaluations, } = orcha.supportAgent.run("Help me with my order."); const finalResult = await result; ``` - `sessionId` — available immediately; save it to continue or inspect the session. - `stream` — a `ReadableStream` of live output and status snapshots. - `snapshot` — the latest snapshot emitted by `stream`, or `undefined` before the first one arrives. - `result` — a promise for the final state of this run. - `evaluations` — a separate promise for evaluations configured on the agent. Now narrow `finalResult.status` before reading status-specific fields: ```ts if (finalResult.status === "completed") { const { sessionId, output, usage } = finalResult; console.log(output); } ``` ## API reference ### Input ```ts run(input: string | { content: string | MessageContent | MessageContent[]; name?: string; metadata?: Record; variables?: Record; clientCapabilities?: Array; }): Execution ``` - `content` — the first user message. It can be text or supported multimodal content. - `name` — an optional human-readable session name. - `metadata` — searchable application data. Do not store secrets here. - `variables` — values for `{{ variableName }}` placeholders in the agent's instructions. They are fixed when the session is created. - `clientCapabilities` — client action names this caller can handle. Calling `.run()` again creates a different session. Use [`resume()`](/docs/sessions/resume) to continue an existing one. ### Execution ```ts type Execution = { sessionId: string; stream: ReadableStream>; snapshot: ExecutionSnapshot | undefined; result: Promise>; evaluations: Promise; }; ``` The stream can emit: - `{ status: "streaming", sessionId, output }` while output is arriving. - `{ status: "waiting_for_subagent", sessionId, childSessionId, childAgent }` while a child agent is running. - Any final result described below. ### Final result ```ts type RunResult = | { status: "completed"; sessionId: string; output: TOutput; usage?: Usage; } | { status: "waiting_for_client_action"; sessionId: string; output?: TOutput; usage?: Usage; clientToolCalls: ClientToolCall[]; } | { status: "paused"; sessionId: string; output?: TOutput; usage?: Usage; } | { status: "failed"; sessionId: string; error: RunError; }; ``` - `output` — final text for a text agent or parsed data for a JSON agent. A paused run can contain partial output. - `clientToolCalls` — actions your client must resolve before the run can continue. - `usage` — token usage for the run. - `error` — structured failure information. ```ts type Usage = { inputTokens: number; outputTokens: number; reasoningTokens: number | null; cacheReadTokens: number; cacheWriteTokens: number; }; type RunError = { code: | "invalid_input" | "unsupported_content_type" | "unsupported_provider_capability" | "session_not_found" | "session_busy" | "client_action_required" | "missing_tool_results" | "unknown_call_id" | "invalid_tool_result" | "action_result_conflict" | "session_completed" | "provider_error" | "storage_error" | "aborted" | "execution_failed"; message: string; retryable: boolean; details?: Record; }; ``` ### Evaluations `execution.result` does not wait for evaluations. Await `execution.evaluations` when your process needs the scores before exiting: ```ts type EvaluationResult = { name: string; status: "passed" | "failed" | "error"; metrics: Array<{ name: string; score: number; threshold: number; passed: boolean; reasoning: string; evidence: string[]; }>; usage?: Usage; durationMs: number; error?: { message: string; }; }; ``` --- # Resume a session Resume an OrchaJS session with .resume(), including human-in-the-loop client actions. Source: https://orcha.sh/docs/sessions/resume Markdown: https://orcha.sh/docs/sessions/resume.mdx Use `.resume()` with a saved `sessionId` to continue the same conversation: ```ts const result = await orcha.supportAgent.resume(sessionId, { content: "What should I do next?", }).result; ``` Orcha loads the durable context automatically. Do not send previous messages again. ## Run, resolve a client action, and resume A client action moves work into your application. The following is the entire flow in one place: ```ts // 1. Start the session. let result = await orcha.approvalAgent.run({ content: "Approve a $750 laptop.", clientCapabilities: ["request_human_approval"], }).result; // 2. The agent paused and requested work from your client. if (result.status === "waiting_for_client_action") { const call = result.clientToolCalls[0]; if (call.name === "request_human_approval") { // Resolve this in your UI, mobile app, worker, or other client. const approved = await showApprovalDialog(call.arguments); // 3. Return the result and continue the same run. result = await orcha.approvalAgent.resume(result.sessionId, { toolResults: [ { callId: call.callId, output: { approved, note: "Decision submitted by the user.", }, }, ], }).result; } } if (result.status === "completed") { console.log(result.output); } ``` Use `call.name` to identify the requested client action. `call.arguments` matches that action's `parameters`; the returned `output` must match its `outputSchema`. For example, a location action can return the fields defined by its own schema: ```ts { callId: call.callId, output: { latitude: 28.6139, longitude: 77.209, }, } ``` ## Resolve multiple client actions Return one result for every requested call in one `.resume()`: ```ts if (result.status === "waiting_for_client_action") { const toolResults = await Promise.all( result.clientToolCalls.map(async (call) => { const output = await handleClientAction(call.name, call.arguments); return { callId: call.callId, output, }; }), ); const next = await orcha.supportAgent.resume(result.sessionId, { toolResults, }).result; } ``` Every pending `callId` must appear exactly once. ## When a client action fails Keep normal results simple. Add `isError: true` only when your client could not perform the action: ```ts { callId: call.callId, output: { message: "The user denied location access.", }, isError: true, } ``` The agent receives that failure and can decide what to do next. ## API reference ### Continue the conversation ```ts resume( sessionId: string, input?: string | { content: string | MessageContent | MessageContent[]; clientCapabilities?: Array; }, ): Execution ``` - `sessionId` — the existing session to continue. - `content` — the next user message. - `clientCapabilities` — client actions available for this resumed run. - Omitting `input` asks the agent to `"Continue."`. A conversational resume starts a new numbered run in the same session. ### Resolve pending client actions ```ts resume( sessionId: string, input: { toolResults: Array<{ callId: string; output: ClientActionOutput; isError?: boolean; }>; }, ): Execution ``` - `callId` — copy it unchanged from the requested call. - `output` — data matching that client action's `outputSchema`. - `isError` — optional; use `true` only when the client action failed. Do not combine `content` and `toolResults`. While actions are pending, resolve them before sending another conversational message. ### Requested call ```ts type ClientToolCall = { callId: string; name: string; arguments: Record; }; ``` - `callId` uniquely pairs the request with its result. - `name` is the client action name from its `index.json`. - `arguments` matches the action's `parameters` schema. ### Result `.resume()` returns the same `Execution` and `RunResult` shapes as [`run()`](/docs/sessions/start): - `completed` — read `result.output`. - `waiting_for_client_action` — resolve the new `clientToolCalls`. - `paused` — the session was explicitly paused. - `failed` — inspect `result.error`. Common client-action errors include missing results, an unknown or duplicated `callId`, output that does not match the action schema, and trying to send content while actions remain pending. --- # Read a session Read an OrchaJS session snapshot with .get() for status, output, and pending client actions. Source: https://orcha.sh/docs/sessions/get Markdown: https://orcha.sh/docs/sessions/get.mdx Use `.get()` to read the latest session state without starting another run: ```ts const session = await orcha.supportAgent.get(sessionId); console.log(session.status); console.log(session.lastOutput); ``` This is useful when restoring a page after a refresh, checking background work, or finding a pending client action. ## Example snapshot ```ts { sessionId: "ses_01K...", // The durable session ID. agent: "supportAgent", // Registered agent key. name: "Order ord_1001", // Optional display name. status: "active", // Overall session state. metadata: { customerId: "cus_123" }, // Application data you attached. createdAt: "2026-09-28T12:00:00Z", // ISO creation time. updatedAt: "2026-09-28T12:01:12Z", // ISO time of the latest event. runStatus: "completed", // State of the latest run. pendingClientActions: [], // Client actions still waiting. lastOutput: "Your order has shipped.", // Latest assistant output. usage: { // Latest run token usage. inputTokens: 320, outputTokens: 42, reasoningTokens: null, cacheReadTokens: 0, cacheWriteTokens: 0, }, } ``` ## Restore a pending action ```ts const session = await orcha.supportAgent.get(sessionId); if (session.runStatus === "waiting_for_client_action") { const call = session.pendingClientActions[0]; console.log(call.name, call.arguments); } ``` Resolve it with [`resume()`](/docs/sessions/resume). ## API reference ```ts get(sessionId: string): Promise type SessionSnapshot = { sessionId: string; agent: string; name?: string; status: "active" | "paused" | "completed"; metadata: Record; createdAt: string; updatedAt: string; runStatus?: | "running" | "waiting_for_subagent" | "waiting_for_client_action" | "paused" | "completed" | "failed"; pendingClientActions: ClientToolCall[]; lineage?: { origin: "delegated"; parentAgent: string; parentSessionId: string; parentCallId: string; }; lastOutput?: AgentOutput; usage?: Usage; }; type ClientToolCall = { callId: string; name: string; arguments: Record; }; type Usage = { inputTokens: number; outputTokens: number; reasoningTokens: number | null; cacheReadTokens: number; cacheWriteTokens: number; }; ``` ### Status fields `status` describes the durable session: - `active` — available, waiting for a client action, or currently running. - `paused` — explicitly paused with `.pause()`. - `completed` — its lifecycle is complete. `runStatus` describes only the latest run: - `running` — the model is working. - `waiting_for_subagent` — a child agent is working. - `waiting_for_client_action` — your client must return tool results. - `paused` — work was explicitly paused. - `completed` — the latest run finished normally. - `failed` — the latest run failed. ### Optional fields - `lineage` exists on delegated subagent sessions and points back to the parent. - `lastOutput` is text for text agents or parsed data for JSON agents. - `usage` can be absent before the session has recorded model usage. - `runStatus` can be absent before the first run starts. `.get()` throws `session_not_found` when the ID does not belong to this registered agent. --- # Read conversation history Render OrchaJS conversation history with .history() for messages, actions, and skills. Source: https://orcha.sh/docs/sessions/history Markdown: https://orcha.sh/docs/sessions/history.mdx Use `.history()` to render a conversation in your application: ```ts const history = await orcha.supportAgent.history(sessionId, { page: 1, pageSize: 25, }); for (const item of history.items) { if (item.type === "message") { console.log(item.role, item.content); } if (item.type === "client_action") { console.log(item.name, item.callId, item.status); } } ``` `history()` removes low-level provider bookkeeping. Its items represent messages and useful agent activity such as actions, skills, subagents, and evaluations. ## Example response ```ts { items: [ { id: "message:3", // Stable item ID. type: "message", // How to interpret this item. createdAt: "2026-09-28T12:00:04Z", // ISO timestamp. role: "user", // "user" or "assistant". content: [ { type: "text", text: "Where is my order?" }, ], }, { id: "client-action:call_123", type: "client_action", createdAt: "2026-09-28T12:00:09Z", name: "request_human_approval", callId: "call_123", status: "waiting", arguments: { amount: 750, currency: "USD" }, summary: "request human approval is waiting for the client.", }, ], page: 1, // Current page. pageSize: 25, // Maximum items on this page. total: 2, // Total projected history items. hasMore: false, // Whether an older page exists. // The current SessionSnapshot is also included here. sessionId: "ses_01K...", agent: "supportAgent", status: "active", metadata: {}, createdAt: "2026-09-28T12:00:00Z", updatedAt: "2026-09-28T12:00:09Z", runStatus: "waiting_for_client_action", pendingClientActions: [ { callId: "call_123", name: "request_human_approval", arguments: { amount: 750, currency: "USD" }, }, ], } ``` ## Pagination Page 1 contains the newest page. Higher page numbers move backward through the session: ```ts const older = await orcha.supportAgent.history(sessionId, { page: 2, pageSize: 50, }); ``` Use [`events()`](/docs/sessions/events) when you need the canonical event log instead of a user-facing history. ## API reference ```ts history( sessionId: string, options?: { page?: number; pageSize?: number; }, ): Promise type SessionHistory = SessionSnapshot & { items: SessionHistoryItem[]; page: number; pageSize: number; total: number; hasMore: boolean; }; ``` - `page` defaults to `1`. - `pageSize` defaults to `50` and accepts `1` through `100`. - Pages are newest-first: page 2 is older than page 1. - Snapshot fields describe the session at the time of the request. ### History item ```ts type SessionHistoryItem = { id: string; type: | "message" | "action" | "client_action" | "subagent" | "skill" | "evaluation" | "session_completed"; createdAt: string; role?: "user" | "assistant"; content?: MessageContent[]; name?: string; status?: "running" | "waiting" | "paused" | "completed" | "failed"; summary?: string; callId?: string; childSessionId?: string; arguments?: Record; durationMs?: number; usage?: Usage; metrics?: EvaluationMetric[]; }; ``` All items contain `id`, `type`, and `createdAt`. Other fields depend on `type`: - `message` — `role`, `content`, and assistant `usage` when available. - `action` — `name`, `callId`, `status`, `arguments`, `durationMs`, and `summary` as available. - `client_action` — `name`, `callId`, `status`, pending `arguments`, and `summary`. - `subagent` — `name`, `childSessionId`, `callId`, `status`, `usage`, and `summary`. - `skill` — `name`, `status`, and `summary`. - `evaluation` — `name`, `status`, `metrics`, `durationMs`, and `summary`. - `session_completed` — completion `status` and `summary`. ### Message content ```ts type MessageContent = | { type: "text"; text: string } | { type: "image" | "video" | "audio" | "url"; mimeType: string; fileUri: string; } | { type: "file"; filePath: string; mimeType: string; }; ``` --- # List sessions List OrchaJS durable sessions with .list() and filter by status or metadata. Source: https://orcha.sh/docs/sessions/list Markdown: https://orcha.sh/docs/sessions/list.mdx Use `.list()` to show sessions created by one registered agent: ```ts const sessions = await orcha.supportAgent.list({ page: 1, pageSize: 25, }); for (const session of sessions.items) { console.log(session.name, session.status); } ``` ## Filter sessions Find paused sessions: ```ts const paused = await orcha.supportAgent.list({ status: "paused", }); ``` Find sessions attached to one application record: ```ts const customerSessions = await orcha.supportAgent.list({ metadata: { customerId: "cus_123", }, }); ``` Filters can be combined: ```ts const work = await orcha.supportAgent.list({ status: "active", metadata: { customerId: "cus_123", priority: "high", }, }); ``` ## Example response ```ts { items: [ { sessionId: "ses_01K...", agent: "supportAgent", name: "Order ord_1001", status: "active", metadata: { customerId: "cus_123" }, createdAt: "2026-09-28T12:00:00Z", updatedAt: "2026-09-28T12:04:00Z", runStatus: "completed", pendingClientActions: [], lastOutput: "Your order has shipped.", usage: { inputTokens: 320, outputTokens: 42, reasoningTokens: null, cacheReadTokens: 0, cacheWriteTokens: 0, }, }, ], page: 1, // Current page. pageSize: 25, // Maximum items on this page. total: 1, // Sessions matching the filters. hasMore: false, // Whether another page exists. } ``` ## API reference ```ts list(options?: { page?: number; pageSize?: number; status?: "active" | "paused" | "completed"; metadata?: Record; }): Promise type SessionList = { items: SessionSnapshot[]; page: number; pageSize: number; total: number; hasMore: boolean; }; ``` - `page` defaults to `1`. - `pageSize` defaults to `50` and accepts `1` through `100`. - `status` matches the durable session status, not `runStatus`. - `metadata` matches sessions containing the supplied key-value pairs. - `items` contains complete [`SessionSnapshot`](/docs/sessions/get) objects. - `total` is the total number matching the filters, not just this page. - `hasMore` indicates whether the next page exists. `.list()` is scoped to the registered agent it is called on. `orcha.supportAgent.list()` does not return sessions owned by another top-level agent. --- # Update a session Update an OrchaJS session name or metadata with .update() without starting a new run. Source: https://orcha.sh/docs/sessions/update Markdown: https://orcha.sh/docs/sessions/update.mdx Use `.update()` to change the name or application metadata of a session: ```ts const session = await orcha.supportAgent.update(sessionId, { name: "Escalated order ord_1001", metadata: { priority: "urgent", assignedTeam: "fulfillment", }, }); ``` The returned value is the updated [`SessionSnapshot`](/docs/sessions/get). ## Update one field Metadata is merged, so you only need to send fields that changed: ```ts const session = await orcha.supportAgent.update(sessionId, { metadata: { priority: "resolved", }, }); console.log(session.metadata); // { // customerId: "cus_123", Existing value remains. // priority: "resolved", Supplied value is updated. // } ``` Use `null` as an application-level empty value: ```ts await orcha.supportAgent.update(sessionId, { metadata: { assignedTeam: null, }, }); ``` This sets the value to `null`; it does not remove the key. ## API reference ```ts update( sessionId: string, update: { name?: string; metadata?: Record; }, ): Promise ``` - `sessionId` — the existing session to update. - `name` — replaces the current display name. - `metadata` — shallowly merges supplied keys into existing metadata. - At least one of `name` or `metadata` is required. - Metadata values must be strings, finite numbers, booleans, or `null`. - The promise resolves with the complete updated snapshot. Every successful update appends a durable `session.updated` event. Updating name or metadata does not start a run, send a model request, or alter the conversation. Do not store secrets in session metadata. --- # Pause a session Pause an OrchaJS session with .pause() and continue the same durable conversation later. Source: https://orcha.sh/docs/sessions/pause Markdown: https://orcha.sh/docs/sessions/pause.mdx Use `.pause()` to safely stop active work: ```ts const session = await orcha.supportAgent.pause(sessionId); console.log(session.status); // "paused" ``` Orcha preserves what happened before the pause. You can continue the same session later. ## Continue later ```ts const result = await orcha.supportAgent.resume(sessionId, { content: "Continue, but keep the answer under three bullets.", }).result; if (result.status === "completed") { console.log(result.output); } ``` If the session is waiting for a client action, return its tool results instead. A new message cannot skip pending client actions. ## What gets paused - Active provider work is aborted. - Active child-agent work is paused too. - Streamed output is preserved as an incomplete assistant message. - `run.paused` and `session.paused` events are recorded. - The returned snapshot has `status: "paused"` and `runStatus: "paused"`. Calling `.pause()` on an already paused session safely returns its current snapshot. ## API reference ```ts pause(sessionId: string): Promise ``` - `sessionId` — the session to stop. - The promise waits until active work has stopped and durable pause events have been saved. - It resolves with the complete [`SessionSnapshot`](/docs/sessions/get). - Calling it again is idempotent: an already paused session returns its current snapshot. - `session_not_found` is thrown when the ID does not belong to this agent. Pausing does not delete the session or its output. Resume it with [`resume()`](/docs/sessions/resume). --- # Debug, audit, and replay Read OrchaJS JSONL session events with .events() for debugging, audit, and replay. Source: https://orcha.sh/docs/sessions/events Markdown: https://orcha.sh/docs/sessions/events.mdx Use `.events()` when you need the exact durable record for auditing, debugging, or replay: ```ts const page = await orcha.supportAgent.events(sessionId, { page: 1, pageSize: 100, }); for (const event of page.events) { console.log(event.sequence, event.type, event.data); } ``` These are the pure events stored by the default Node runtime at: ```text .orcha/sessions//.jsonl ``` This append-only event stream is not just a debug log. Orcha derives the agent's functioning session state, history, pending client actions, usage, and resumable context from it. Use `.history()` for normal conversation UI. Use `.events()` when the exact internal timeline matters. ## Example response ```ts { events: [ { sequence: 1, // Position in this session. type: "session.created", // What happened. timestamp: "2026-09-28T12:00:00Z", // ISO timestamp. data: { schemaVersion: 1, sessionId: "ses_01K...", agent: "supportAgent", status: "active", metadata: {}, variables: {}, }, }, { sequence: 2, type: "run.started", timestamp: "2026-09-28T12:00:01Z", run: 1, // Numbered run in the session. data: { status: "running", agent: "supportAgent", provider: "anthropic", model: "claude-sonnet-4-6", region: "global", outputType: "text", clientCapabilities: [], }, }, ], throughSequence: 12, // Stable upper boundary for pagination. page: 1, pageSize: 100, total: 12, hasMore: false, // The current SessionSnapshot is included too. sessionId: "ses_01K...", agent: "supportAgent", status: "active", metadata: {}, createdAt: "2026-09-28T12:00:00Z", updatedAt: "2026-09-28T12:00:08Z", runStatus: "completed", pendingClientActions: [], } ``` ## Paginate against a stable session Sessions can receive new events while you read older pages. Keep the `throughSequence` returned by the first request and send it with later pages: ```ts const latest = await orcha.supportAgent.events(sessionId, { page: 1, pageSize: 100, }); const older = await orcha.supportAgent.events(sessionId, { page: 2, pageSize: 100, throughSequence: latest.throughSequence, }); ``` This keeps every page within the same event boundary. Page 1 is the newest page; higher page numbers move backward. Most product interfaces should use [`history()`](/docs/sessions/history) instead. Do not read `.orcha` storage files directly. ## API reference ```ts events( sessionId: string, options?: { page?: number; pageSize?: number; throughSequence?: number; }, ): Promise type SessionEvents = SessionSnapshot & { events: SessionEvent[]; throughSequence: number; page: number; pageSize: number; total: number; hasMore: boolean; }; ``` - `page` defaults to `1`. - `pageSize` defaults to `50` and accepts `1` through `100`. - `throughSequence` fixes the newest event included across paginated calls. - `total` counts events inside that sequence boundary. - Snapshot fields describe the current session. ### Event envelope ```ts type SessionEvent = { sequence: number; type: SessionEventType; timestamp: string; run?: number; data: Record; }; ``` - `sequence` is unique and strictly ordered within one session. - `type` identifies the event and the shape of `data`. - `timestamp` is an ISO timestamp. - `run` identifies the numbered run. Session-level events omit it. - `data` is the typed payload for that event. ### Event types Session lifecycle: ```ts "session.created" "session.updated" "session.paused" "session.resumed" ``` Run lifecycle: ```ts "run.started" "run.paused" "run.completed" "run.failed" ``` Messages and actions: ```ts "message.created" "action.requested" "action.completed" "action.failed" "client_action.requested" "client_action.resolved" ``` Skills, evaluations, and subagents: ```ts "skill.requested" "skill.loaded" "skill.failed" "evaluation.requested" "evaluation.completed" "evaluation.failed" "subagent.initiated" "subagent.resumed" "subagent.completed" "subagent.paused" "subagent.failed" ``` Tests can additionally write `test.warning` and `test.completed`. ### Important payloads ```ts // message.created { role: "user" | "assistant" | "tool"; content: MessageContent[] | ToolResult[]; // Assistant messages can also include provider, model, usage, // durationMs, stopReason, responseId, status, and parsedOutput. } // client_action.requested { status: "waiting"; calls: Array<{ callId: string; name: string; arguments: Record; }>; localResults: ToolResult[]; toolCallOrder: string[]; } // client_action.resolved { status: "completed"; results: ToolResult[]; } // run.paused { status: "waiting_for_client_action" | "paused"; clientToolCalls?: ClientToolCall[]; output?: AgentOutput; usage?: Usage; durationMs?: number; } // run.failed { status: "failed"; durationMs: number; usage?: Usage; error: { code: string; message: string; retryable?: boolean; }; } ``` Treat the event log as append-only. Consume events by `sequence`; never edit or infer storage filenames. --- # CLI OrchaJS CLI reference for init, playground, run, test, and production builds. Source: https://orcha.sh/docs/cli Markdown: https://orcha.sh/docs/cli.mdx Run commands through `npx orcha` or package scripts. ## `orcha init` ```bash npx orcha init ``` Adds a minimal `orcha/` registry, an example agent, `AGENTS.md`, and the `.orcha/` gitignore entry. Existing files are skipped, not overwritten. ## `orcha dev` ```bash npx orcha dev ``` Validates the registry and watches `orcha/**`. This is offline and does not call a model. ## `orcha playground` ```bash npx orcha playground npx orcha playground --host localhost --port 4310 --no-open ``` Starts the local development UI. Defaults to `localhost:4310` and opens the browser. ## `orcha run` Start a session: ```bash npx orcha run orderSupport --input "Where is ord_1001?" ``` Use structured or multimodal input from a file: ```bash npx orcha run orderSupport --input-file request.json ``` Continue a session: ```bash npx orcha run orderSupport \ --session ses_123 \ --input "What should I do next?" ``` Submit client-action results: ```bash npx orcha run orderSupport \ --session ses_123 \ --tool-results tool-results.json ``` `tool-results.json`: ```json [ { "callId": "call_123", "output": { "approved": true, "note": "Approved by support lead" } } ] ``` Add `--json` for machine-readable `{ result, evaluations }` output. ## `orcha test` ```bash npx orcha test npx orcha test orderSupport npx orcha test orderSupport/delayedOrder npx orcha test orderSupport/delayedOrder --json ``` Tests call real providers and may consume tokens. Unmocked local actions execute live. ## `orcha build` ```bash npx orcha build ``` Performs offline production compilation and writes `.orcha/dist/bundle.js`. It does not call a provider. ## Suggested scripts ```json { "scripts": { "dev": "orcha playground", "build": "orcha build", "test": "orcha test", "orcha:dev": "orcha dev", "orcha:test": "orcha test" } } ```