# Getting started

Install AML and resolve a credential-free workflow before connecting a real Agent provider.
Canonical: https://agent-markup-language.com/docs/getting-started/
Documentation index: https://agent-markup-language.com/docs/
Complete documentation: https://agent-markup-language.com/docs/llms.txt

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`](https://agent-markup-language.com/docs/reference/runtime/); an optional CLI path then runs an exported tree without application glue. You will finally swap in a real [Agent provider](https://agent-markup-language.com/docs/providers/agents/) without changing the authored AML tree.

## Prerequisites

- Node.js **26 or newer**
- an ESM project (`"type": "module"` in `package.json`)
- TypeScript if you author `.tsx`

**Caution — AML is ESM-only**

CommonJS `require()` is not a supported package entrypoint. Use ESM imports and a TSX-capable runner or compile the
project before running it.

If a coding agent will author or review the workflow, optionally install the [AML authoring skill](https://agent-markup-language.com/docs/agent-skill/). The skill teaches the agent the current public API and safety boundaries; it does not replace the SDK installation below.

## 1. Create a project

**npm**

```sh title="Terminal"
mkdir aml-first-workflow
cd aml-first-workflow
npm init -y
npm pkg set type=module
npm install @aml-jsx/sdk
npm install --save-dev typescript vite-node
```

**pnpm**

```sh title="Terminal"
mkdir aml-first-workflow
cd aml-first-workflow
pnpm init
pnpm add @aml-jsx/sdk
pnpm add --save-dev typescript vite-node
```

Add `"type": "module"` to `package.json`.

**Note — pnpm may require build-script approval**

pnpm 11 can stop the install with `ERR_PNPM_IGNORED_BUILDS` when it blocks transitive native build scripts. Run `pnpm
approve-builds`, approve the dependencies named by pnpm, then run `pnpm install` again. This is pnpm's installation
policy; AML does not execute those scripts at runtime.

Create `tsconfig.json`:

```json title="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`:

```json title="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.

## 2. Evaluate your first tree

Create `src/first-workflow.tsx`:

```tsx title="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:

```sh title="Terminal"
npm run aml
# or: pnpm aml
```

Expected output:

```text title="Output"
Resolved: Explain what AML evaluates.
```

1. JSX creates an AML node tree; it does not run `<Agent />` during rendering.
2. `AmlRuntime.evaluate()` validates and resolves the tree.
3. [`<Agent />`](https://agent-markup-language.com/docs/reference/primitives/agent/) builds a normalized request from its system text, prompt, capabilities, and effective scopes.
4. The selected provider returns an `AgentResponse`; the runtime returns its text from the root.
5. The runtime releases acquired resources in reverse order.

The [`DeterministicAgentProvider`](https://agent-markup-language.com/docs/reference/testing/#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.

### Run the same tree with the CLI

The application above constructs `AmlRuntime` because it owns the process. For a standalone workflow file, install the experimental CLI beside the SDK:

```sh title="Terminal"
npm install --save-dev @aml-jsx/cli
```

Create `src/cli-workflow.tsx`. Put the provider directly on [`<Agent />`](https://agent-markup-language.com/docs/reference/primitives/agent/), export the tree, and let the CLI create and instrument the runtime:

```tsx title="src/cli-workflow.tsx"
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:

```sh title="Terminal"
npx aml run ./src/cli-workflow.tsx
```

Expected output on standard output:

```text title="Output"
Resolved: Explain what AML evaluates.
```

**Caution — Do not create a second runtime inside a CLI workflow**

Export the AML tree itself. Calling `new AmlRuntime().evaluate(...)` inside the exported function creates a separate
nested evaluation, so the CLI cannot trace, cancel, or configure the Agent work it was intended to own. The complete
export, environment, and output contract is in the [CLI guide](https://agent-markup-language.com/docs/cli/).

## 3. Connect a real Agent

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.

**Note — There is no universal default provider**

Start with the coding harness and model account you already operate. The Codex tab is the shortest path when you have
an OpenAI API key; choose OpenCode for its model catalog and native tool policy, or Pi for its extensible Tool and MCP
path. The provider comparison explains the trade-offs in detail.

**Codex**

```tsx title="src/first-workflow.tsx"
import { Agent, AmlRuntime, codexAgent } from "@aml-jsx/sdk"

const apiKey = process.env.OPENAI_API_KEY
if (!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:

```sh
npm install --global @agentclientprotocol/codex-acp@1.4.0 @openai/codex@0.147.0
codex-acp --help
codex --version
export OPENAI_API_KEY="your-development-key"
npm run aml
```

Do not commit the key or place it in a Workspace. See the [Codex guide](https://agent-markup-language.com/docs/providers/agents/codex/) for executable overrides, `CODEX_API_KEY`, model precedence, permissions, and Sandbox compatibility.

**OpenCode**

```tsx title="src/first-workflow.tsx"
import { Agent, AmlRuntime, opencodeAgent } from "@aml-jsx/sdk"

const apiKey = process.env.OPENCODE_API_KEY
if (!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:

```sh
npm install --global opencode-ai@1.18.18
opencode --version
export OPENCODE_API_KEY="your-development-key"
npm run aml
```

This 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](https://agent-markup-language.com/docs/providers/agents/opencode/) documents both approaches, its generated profile, permission mapping, and state isolation.

**Pi**

```tsx title="src/first-workflow.tsx"
import { Agent, AmlRuntime, piAgent } from "@aml-jsx/sdk"

const apiKey = process.env.OPENCODE_API_KEY
if (!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:

```sh
npm install --global pi-acp@0.0.33 @earendil-works/pi-coding-agent@0.84.2
pi --version
command -v pi-acp
export OPENCODE_API_KEY="your-development-key"
npm run aml
```

This 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](https://agent-markup-language.com/docs/providers/agents/pi/) explains when AML generates a wrapper and how to install `pi-mcp-adapter` for Tools, authored MCP servers, or structured output.

**Tip — Provider selection is lexical too**

Set a default on `AmlRuntime`, or pass `provider` directly to an `<Agent />` when one subtree needs a different model
harness. A direct prop wins over the runtime default. Compare the built-in profiles in [Choose an
Agent](/docs/providers/agents/).

## 4. Add files and command execution

[`<File />`](https://agent-markup-language.com/docs/reference/primitives/file/) writes through the nearest active [`<Workspace />`](https://agent-markup-language.com/docs/reference/primitives/workspace/) or [`<Sandbox />`](https://agent-markup-language.com/docs/reference/primitives/sandbox/) filesystem. [`<Script />`](https://agent-markup-language.com/docs/reference/primitives/script/) can run directly on the trusted host, but this example deliberately uses a fresh Workspace directory and scopes command execution to that materialization.

```tsx title="src/resources.tsx"
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)
```

**Danger — Local Sandbox is trusted host execution**

[`localSandbox()`](https://agent-markup-language.com/docs/providers/sandboxes/local/) starts ordinary host processes with your application's
privileges. AML validates logical Workspace paths, but it does not isolate the process, environment, network, or host
filesystem. Use only trusted commands and read the [Sandbox security guidance](https://agent-markup-language.com/docs/production/security/).

## Where to go next

**Understand evaluation**

Learn post-order resolution, lexical scopes, concurrency, and cleanup in [Core concepts](https://agent-markup-language.com/docs/concepts/).

**Build from a recipe**

Copy a complete workflow from the [Cookbook](https://agent-markup-language.com/docs/cookbook/), with expected output and provider requirements.

**Choose infrastructure**

Compare the complete [provider catalog](https://agent-markup-language.com/docs/providers/) across Agent, Sandbox, and Workspace responsibilities.

**Prepare production**

Review isolation, secrets, persistence, cancellation, and telemetry in [Production](https://agent-markup-language.com/docs/production/).

**Run workflow files**

Use the [experimental CLI](https://agent-markup-language.com/docs/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](https://agent-markup-language.com/docs/agent-skill/) before asking an agent to generate or review AML
code.
