# CLI (experimental)

Run trusted AML TypeScript, TSX, and JavaScript workflow files directly with the experimental @aml-jsx/cli package.
Canonical: https://agent-markup-language.com/docs/cli/
Documentation index: https://agent-markup-language.com/docs/
Complete documentation: https://agent-markup-language.com/docs/llms.txt

`@aml-jsx/cli` runs an AML workflow source file without a separate application entry point. It loads TypeScript, TSX, or JavaScript through Vite and `vite-node`, resolves one exported AML value, evaluates it, and prints the result.

**Caution — Experimental package**

The CLI is packaged separately from the SDK. Its command and export contracts may change while it remains
experimental. Use the explicit [`AmlRuntime` application pattern](https://agent-markup-language.com/docs/runtime/) when you need a stable production
entry point or complete control over runtime construction.

## What the CLI owns

The CLI deliberately owns only process-level concerns:

- loading a trusted workflow module;
- applying Vite-style environment files before the module is evaluated;
- selecting the default, `main`, or requested named export;
- creating an [`AmlRuntime`](https://agent-markup-language.com/docs/reference/runtime/), evaluating the exported AML value, and formatting the result;
- translating process interruption into runtime cancellation so active resources can be released;
- writing lifecycle and optional trace diagnostics to standard error.

Provider selection and provider-specific options belong in the workflow file. The CLI does not have `--agent-provider`, `--sandbox-provider`, model, credential, or Workspace configuration flags.

## Run the package

Install the CLI beside the SDK used by the workflow:

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

Run it through the project-local executable:

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

From an AML repository checkout, contributors can build and invoke the workspace copy directly:

```sh
npm run build --workspace=@aml-jsx/cli
node apps/cli/dist/index.js run ./workflow.tsx
```

## Write a workflow entry

Export an AML renderable directly or export a zero-argument function that returns one. The current CLI creates the `AmlRuntime`; the module does not export a runtime instance.

```tsx title="workflow.tsx"
import { Agent } from "@aml-jsx/sdk"
import { DeterministicAgentProvider } from "@aml-jsx/sdk/testing"

const provider = new DeterministicAgentProvider({
  name: "cli-example",
  respond: request => ({ text: `Reviewed: ${request.prompt}` }),
})

export default <Agent provider={provider}>README.md</Agent>
```

This credential-free example prints `Reviewed: README.md`. Replace the deterministic provider with a [supported Agent provider](https://agent-markup-language.com/docs/providers/agents/) when the workflow is ready to call a live model. Keeping provider construction in the module makes the executable workflow self-contained: another runner can import the same tree, inspect its provider construction, or evaluate it with application-owned infrastructure later.

**Note — Runtime defaults are not part of the current export contract**

[`AmlRuntime`](https://agent-markup-language.com/docs/reference/runtime/) supports default [Agent](https://agent-markup-language.com/docs/providers/agents/),
[Sandbox](https://agent-markup-language.com/docs/providers/sandboxes/), and [Workspace](https://agent-markup-language.com/docs/providers/workspaces/) providers, but the experimental
CLI currently constructs an empty runtime internally. A CLI workflow must therefore put the required providers on its
AML components. A future workflow descriptor could expose runtime options without adding provider-specific command
flags, but that contract is not implemented today.

**Caution — Export the tree, not a nested runtime evaluation**

Do not call `new AmlRuntime().evaluate(...)` inside the exported function. That starts an independent run before the
  CLI evaluates the returned text, preventing CLI tracing, cancellation, and runtime ownership from covering the Agent
  work. Export{" "}

[&lt;Agent /&gt;](https://agent-markup-language.com/docs/reference/primitives/agent/)
{" "}
  directly with `provider={provider}`.

## Export resolution

The command resolves and executes one export in this order:

1. Use the export selected by `--entry`, when supplied.
2. Otherwise use the module's `default` export.
3. Otherwise call an exported `main()` function.
4. Await a selected function or promise and validate that it resolves to an AML renderable.

A function can build the tree after environment variables have been loaded:

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

export default function ReviewRepository() {
  const model = process.env.AML_MODEL
  const OpenCode = opencodeAgent(model ? { model } : {})

  return <Agent provider={OpenCode}>Review this repository and list the three highest-risk changes.</Agent>
}
```

The workflow file is the positional argument immediately after `run`. `--entry` selects an export inside that file; it does not replace the file argument. Select a different named export when one module contains several entry points:

```sh title="Terminal"
aml run ./workflow.tsx --entry releaseReview
```

## Environment loading

Before importing the workflow, the CLI reads Vite-style environment files from the directory containing the workflow file—not necessarily the process's current working directory. The mode is `NODE_ENV`, or `development` when `NODE_ENV` is absent.

```text title="Project layout"
project/
├── .env.ci               # explicit override selected from the current directory
└── src/
    ├── workflow.tsx
    ├── .env              # workflow-local base values
    ├── .env.local        # workflow-local machine values
    ├── .env.development
    └── .env.development.local
```

Existing process environment values win over values in these files. An explicitly selected runtime environment file is applied last and can override both:

```sh title="Terminal"
aml run ./workflow.tsx --runtime-env-file .env.ci
```

The option is named `--runtime-env-file` because modern Node.js interprets `--env-file` before the AML command receives its arguments. Relative override paths are resolved from the current working directory first, then from the workflow directory.

## Run a named workflow in CI

One module can expose several jobs while keeping provider and environment choices in source. This credential-free example selects one named export and echoes its resolved prompt:

```tsx title="src/automation.tsx"
import { Agent } from "@aml-jsx/sdk"
import { DeterministicAgentProvider } from "@aml-jsx/sdk/testing"

const provider = new DeterministicAgentProvider({
  name: "ci-example",
  respond: request => ({ text: request.prompt }),
})

export const releaseReview = (
  <Agent provider={provider}>Review the {process.env.RELEASE_CHANNEL ?? "preview"} release.</Agent>
)

export const dependencyReview = <Agent provider={provider}>Review dependency updates.</Agent>
```

Put `RELEASE_CHANNEL=stable` in `src/.env`, then apply a job-specific override from the process working directory:

```dotenv title=".env.ci"
RELEASE_CHANNEL=release-candidate
```

```sh title="Terminal"
npx aml run ./src/automation.tsx \
  --entry releaseReview \
  --runtime-env-file .env.ci \
  --json \
  --trace
```

The JSON result containing `Review the release-candidate release.` is written to standard output. Lifecycle and metadata-only trace events go to standard error; prompt and result content remain redacted unless `--capture-content` is supplied explicitly.

**Caution — Workflow files are trusted code**

`vite-node` evaluates the module and all of its imports in the CLI process. A Sandbox inside the exported AML tree can
  constrain descendant{" "}

[&lt;Agent /&gt;](https://agent-markup-language.com/docs/reference/primitives/agent/)
{" "}
  and{" "}

[&lt;Script /&gt;](https://agent-markup-language.com/docs/reference/primitives/script/)
{" "}
  execution. An unsandboxed 
&lt;Script /&gt;
 also runs as a trusted host process from the CLI working
  directory; its optional relative 
cwd
 resolves from that directory. The CLI does not sandbox top-level
  JavaScript in the workflow module.

## Source execution

The CLI intentionally has one compiler path: Vite and `vite-node`. It creates a one-shot Vite transform environment,
loads the trusted module with source-map support, closes that environment, and then evaluates the selected AML value.
There is no `--compiler` abstraction. A second loader should only be introduced if native platform evidence demonstrates
a compatibility gap that Vite cannot address.

## Output and diagnostics

Normal output stays easy to pipe: the resolved workflow result is written to standard output, while run lifecycle and trace diagnostics are written to standard error.

```sh title="Terminal"
aml run ./workflow.tsx > result.txt
```

Use `--json` for a machine-readable result envelope containing `runId`, `durationMs`, `success`, and `result`:

```sh title="Terminal"
aml run ./workflow.tsx --json
```

Use `--trace` to print metadata-only trace events. Prompt and result content remains redacted unless content capture is requested explicitly:

```sh title="Terminal"
aml run ./workflow.tsx --trace
aml run ./workflow.tsx --trace --capture-content
```

`--capture-content` is an AML CLI option, not an ACP option or Agent capability. Treat its output as sensitive. It can include prompts, Agent messages and thoughts exposed through ACP, raw Tool activity, plans, structured results, [`<Tool />`](https://agent-markup-language.com/docs/reference/primitives/tool/) input and output, commands, errors, and filesystem context. See [Observability](https://agent-markup-language.com/docs/observability/) for the complete event and redaction contract.

## Interrupting a run

`aml run` translates `SIGINT` (usually `Ctrl`+`C`) and `SIGTERM` into cancellation of the active runtime evaluation. The signal reaches Agent sessions, ACP requests, MCP relays, and Sandbox operations through the evaluation's `AbortSignal`. AML then closes active sessions and releases acquired resource scopes before the CLI exits.

The first signal starts graceful cancellation and allows up to 10 seconds for cleanup. When cleanup settles, the CLI exits with the conventional signal status: `130` for `SIGINT` or `143` for `SIGTERM`. A second `SIGINT` or `SIGTERM` exits immediately instead of continuing to wait. If cleanup has not settled after 10 seconds, the CLI also forces termination with the first signal's status.

**Caution — Forced termination cannot run JavaScript cleanup**

`SIGKILL`, process crashes, host failure, and power loss bypass the runtime completely. Remote providers should use
platform-side TTLs or reapers, and operators should monitor for local processes, containers, or remote environments
left behind after an ungraceful exit. See [Operations](https://agent-markup-language.com/docs/production/operations/) and [Incident
response](/docs/production/incident-response/).

Cleanup follows provider ownership. AML orchestrates cancellation and invokes the acquired lease's release boundary; the Sandbox provider decides how to stop its platform-specific resources. Local kills tracked process groups, Docker removes its leased container, and disposable remote providers terminate or delete their remote environment. A provider backed by intentionally persistent infrastructure should terminate evaluation-owned executions and release only the evaluation lease, not destroy the shared infrastructure.

## Current command reference

| Command or option           | Behavior                                                                  |
| --------------------------- | ------------------------------------------------------------------------- |
| `aml run <file>`            | Load and evaluate one trusted TS, TSX, or JS workflow module.             |
| `-e, --entry <name>`        | Select a named export instead of the default export resolution.           |
| `--runtime-env-file <file>` | Apply one explicit environment file after Vite-style environment loading. |
| `--trace`                   | Write metadata-only runtime trace events to standard error.               |
| `--capture-content`         | Include sensitive trace content and imply `--trace`.                      |
| `--json`                    | Emit a JSON result envelope instead of plain workflow text.               |
| `-h, --help`                | Show CAC-generated command help.                                          |
| `-v, --version`             | Show the CLI package, platform, architecture, and Node versions.          |

## When to use it

The experimental CLI is useful for local workflows, repository automation, scheduled jobs with explicit environment injection, and examples that should run without handwritten `new AmlRuntime().evaluate(...)` glue.

Prefer an application-owned runner when you need to inject runtime defaults, attach custom event sinks, share one runtime configuration across requests, coordinate service shutdown, or expose AML behind an API or queue consumer. Read [Deployment](https://agent-markup-language.com/docs/production/deployment/) for that pattern.
