Understand evaluation
Learn post-order resolution, lexical scopes, concurrency, and cleanup in Core concepts.
This guide gives you a deterministic first success: no API key, ACP executable, Docker daemon, or remote account required. The main path shows an application-owned AmlRuntime; an optional CLI path then runs an exported tree without application glue. You will finally swap in a real Agent provider without changing the authored AML tree.
"type": "module" in package.json).tsxIf a coding agent will author or review the workflow, optionally install the AML authoring skill. The skill teaches the agent the current public API and safety boundaries; it does not replace the SDK installation below.
mkdir aml-first-workflowcd aml-first-workflownpm init -ynpm pkg set type=modulenpm install @aml-jsx/sdknpm install --save-dev typescript vite-nodemkdir aml-first-workflowcd aml-first-workflowpnpm initpnpm add @aml-jsx/sdkpnpm add --save-dev typescript vite-nodeAdd "type": "module" to package.json.
Create tsconfig.json:
{ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "target": "ES2024", "strict": true, "skipLibCheck": true, "jsx": "react-jsx", "jsxImportSource": "@aml-jsx/sdk" }}The automatic JSX runtime turns AML elements into AML nodes. React is not installed or involved. skipLibCheck skips
checking upstream declaration files loaded by the bundled provider adapters while preserving strict checks for your
project source.
Add one repeatable command to the generated package.json:
{ "type": "module", "scripts": { "aml": "vite-node src/first-workflow.tsx" }}Keep the dependencies added by your package manager when you merge this snippet into the generated file.
Create src/first-workflow.tsx:
import { Agent, AmlRuntime } from "@aml-jsx/sdk"import { DeterministicAgentProvider } from "@aml-jsx/sdk/testing"
const agentProvider = new DeterministicAgentProvider({ name: "first-workflow", respond: request => ({ text: `Resolved: ${request.prompt}` }),})
const runtime = new AmlRuntime({ agentProvider })
const result = await runtime.evaluate(<Agent system="Answer in one sentence.">Explain what AML evaluates.</Agent>)
console.log(result)Run it with the script you just added:
npm run aml# or: pnpm amlExpected output:
Resolved: Explain what AML evaluates.<Agent /> during rendering.AmlRuntime.evaluate() validates and resolves the tree.<Agent /> builds a normalized request from its system text, prompt, capabilities, and effective scopes.AgentResponse; the runtime returns its text from the root.The DeterministicAgentProvider deliberately echoes a known result and records calls. It is part of the public testing entrypoint, making it useful for tutorials, examples, and workflow tests—not just AML’s own test suite.
The application above constructs AmlRuntime because it owns the process. For a standalone workflow file, install the experimental CLI beside the SDK:
npm install --save-dev @aml-jsx/cliCreate src/cli-workflow.tsx. Put the provider directly on <Agent />, export the tree, and let the CLI create and instrument the runtime:
import { Agent } from "@aml-jsx/sdk"import { DeterministicAgentProvider } from "@aml-jsx/sdk/testing"
const provider = new DeterministicAgentProvider({ name: "cli-workflow", respond: request => ({ text: `Resolved: ${request.prompt}` }),})
export default <Agent provider={provider}>Explain what AML evaluates.</Agent>Run the exported workflow:
npx aml run ./src/cli-workflow.tsxExpected output on standard output:
Resolved: Explain what AML evaluates.The authored node remains the same. Replace the contents of src/first-workflow.tsx with one complete tab below, then run the same aml script.
import { Agent, AmlRuntime, codexAgent } from "@aml-jsx/sdk"
const apiKey = process.env.OPENAI_API_KEYif (!apiKey) throw new Error("OPENAI_API_KEY is required")
const runtime = new AmlRuntime({ agentProvider: codexAgent({ apiKey, model: "gpt-5.6-luna", reasoningEffort: "low", }),})const result = await runtime.evaluate(<Agent>Describe this project in three bullets.</Agent>)
console.log(result)Install and verify the ACP adapter version exercised by this repository, then supply a credential through your shell or secret manager:
npm install --global @agentclientprotocol/codex-acp@1.4.0 @openai/codex@0.147.0codex-acp --helpcodex --versionexport OPENAI_API_KEY="your-development-key"npm run amlDo not commit the key or place it in a Workspace. See the Codex guide for executable overrides, CODEX_API_KEY, model precedence, permissions, and Sandbox compatibility.
import { Agent, AmlRuntime, opencodeAgent } from "@aml-jsx/sdk"
const apiKey = process.env.OPENCODE_API_KEYif (!apiKey) throw new Error("OPENCODE_API_KEY is required")
const runtime = new AmlRuntime({ agentProvider: opencodeAgent({ env: { OPENCODE_API_KEY: apiKey }, model: "opencode-go/deepseek-v4-flash", }),})const result = await runtime.evaluate(<Agent>Describe this project in three bullets.</Agent>)
console.log(result)Install and verify the OpenCode executable, then configure a model provider:
npm install --global opencode-ai@1.18.18opencode --versionexport OPENCODE_API_KEY="your-development-key"npm run amlThis tab deliberately uses an environment credential so the complete path is visible. OpenCode also supports native opencode auth login; if you use that path, remove the explicit key guard and environment mapping and select a model configured for the logged-in account. The OpenCode guide documents both approaches, its generated profile, permission mapping, and state isolation.
import { Agent, AmlRuntime, piAgent } from "@aml-jsx/sdk"
const apiKey = process.env.OPENCODE_API_KEYif (!apiKey) throw new Error("OPENCODE_API_KEY is required")
const runtime = new AmlRuntime({ agentProvider: piAgent({ command: "pi-acp", env: { OPENCODE_API_KEY: apiKey }, model: "opencode-go/deepseek-v4-flash", piCommand: "pi", }),})const result = await runtime.evaluate(<Agent>Describe this project in three bullets.</Agent>)
console.log(result)Install and verify the ACP bridge and Pi CLI:
npm install --global pi-acp@0.0.33 @earendil-works/pi-coding-agent@0.84.2pi --versioncommand -v pi-acpexport OPENCODE_API_KEY="your-development-key"npm run amlThis follows the repository smoke path with DeepSeek V4 Flash through OpenCode Go. If you select another Pi model provider, change the model identifier and forward that provider’s credential instead. The Pi guide explains when AML generates a wrapper and how to install pi-mcp-adapter for Tools, authored MCP servers, or structured output.
<File /> writes through the nearest active <Workspace /> or <Sandbox /> filesystem. <Script /> can run directly on the trusted host, but this example deliberately uses a fresh Workspace directory and scopes command execution to that materialization.
import { mkdtemp } from "node:fs/promises"import { tmpdir } from "node:os"import { join } from "node:path"import { AmlRuntime, File, Sandbox, Script, Workspace, localSandbox, localWorkspace } from "@aml-jsx/sdk"
const directory = await mkdtemp(join(tmpdir(), "aml-guide-"))const runtime = new AmlRuntime({ sandboxProvider: localSandbox(), workspaceProvider: localWorkspace({ directory }),})
const output = await runtime.evaluate( <Workspace id="guide" load={false} save={false}> <File path="brief.txt">Inspect this isolated guide directory.</File> <Sandbox access="read-write"> <Script command="node" args={["-e", "console.log('workspace ready')"]} /> </Sandbox> </Workspace>)
console.log(output)Understand evaluation
Learn post-order resolution, lexical scopes, concurrency, and cleanup in Core concepts.
Build from a recipe
Copy a complete workflow from the Cookbook, with expected output and provider requirements.
Choose infrastructure
Compare the complete provider catalog across Agent, Sandbox, and Workspace responsibilities.
Prepare production
Review isolation, secrets, persistence, cancellation, and telemetry in Production.
Run workflow files
Use the experimental CLI when an exported AML tree should run without application entry-point glue.
Work with a coding agent
Install and verify the AML authoring skill before asking an agent to generate or review AML code.