agent markup language | async JSX runtime

Agent workflows
authored as <markup />

Write the workflow you mean. AML brings agents, tools, sandboxes, persistent files, and multi-step logic into one async JSX tree — without tying that workflow to one provider.

AmlRuntime · example leaves-first resolution tree

resolving running resolved cycle 1

<Agent provider={codex}>

<Mcp use={slack} />

post our weekly standup:

{synthesis}

</Agent>

A framework for building complex, provider-agnostic agent workflows.

why aml

Your agent sdk isn’t enough.

Most AI SDKs are designed around chat: send a message, call a model, stream a response. Agentic workflows need much more around that conversation — tools, permissions, sandboxed execution, persistent files, multiple agents, and clear control over how work moves between them. AML brings those pieces into one provider-agnostic runtime, expressed as composable, human-readable XML trees that developers can read, reason about, and reuse.

</>

Write the workflow as reusable components

Package agents, prompts, capabilities, and control flow as ordinary async JSX components. Compose them into larger workflows without hiding how data moves.

Change providers without starting over

Move between OpenCode, Codex, and Pi — or use a deterministic test provider — without rebuilding the workflow around a new SDK.

Give agents a real place to work

Attach sandboxes and persistent workspaces exactly where they’re needed. AML manages their scope, lifecycle, and cleanup.

See what happened

Every run emits structured lifecycle and trace events, so you can inspect a workflow today and build better tooling around it tomorrow.

how it works

Start at the leaves. Work your way back.

AML gives JSX a new job. Instead of describing a user interface, the tree describes an agent workflow—and the runtime resolves it from the leaves up. There’s no new DSL to learn: editors already understand JSX, TypeScript already checks it, and language models already know how to write it.

    <Review /> resolution order

    under the hood

    Simple by design. Flexible by default.

    When an <Agent/> node resolves, the AML Runtime preloads a <Workspace/> into a safe <Sandbox/> and prompts the agent sdk through Agent Client Protocol. The Agent reads files, edits code, and runs commands inside the Sandbox. When the work is done, AML collects the result and saves the Workspace changes. Because every built-in Agent uses the same ACP connection, you can switch Agents or Sandboxes without rewriting the tree.

    1. Your app sends the authored JSX tree to the AML Runtime.
    2. The AML Runtime selects an Agent provider and acquires a Workspace provider.
    3. The Agent provider maps its executable into the shared ACP engine.
    4. The ACP engine starts the Agent process through the Sandbox adapter.
    5. The Workspace provider attaches files to the Sandbox and reconciles them afterward.

    integrations

    Bring your own agent, sandbox, or storage.

    Every built-in Agent runs across every built-in Sandbox. Use OpenCode, Codex, or Pi with trusted local execution, Docker, Daytona, or Modal, then keep files locally or in S3-compatible object storage without rewriting the Agent tree.

    agents

    harnesses & model runtimes

    roadmap →

    sandboxes

    ephemeral execution

    roadmap →

    workspaces

    durable object storage

    roadmap →

    runtime packages

    all from @aml-jsx/sdk

    agent

    sandbox

    workspace

    OpenCode × Local × S3

    any agent on any sandbox with durable files

    main.tsx
    import {  Agent, AmlRuntime, Sandbox, Workspace,  opencodeAgent,  localSandbox,  s3Workspace,} from "@aml-jsx/sdk" const provider = opencodeAgent({ model: "opencode-go/glm-5.1" })const sandbox = localSandbox({ workspace: "./project" })const workspace = s3Workspace({ bucket: "agent-workspaces" })const runtime = new AmlRuntime() await runtime.evaluate(  <Workspace id="thread-42" load save={{ include: ["**/*.md"] }} provider={workspace}>    <Sandbox provider={sandbox}>      <Agent provider={provider}>Summarize this repository.</Agent>    </Sandbox>  </Workspace>,)

    bring your own

    The same contracts are open to custom providers.

    defineAgentProvider() · defineSandboxProvider() · defineWorkspaceProvider() ↗

    reference

    Small enough to learn in one sitting

    Eleven primitives and a focused set of runtime APIs. Everything else is ordinary JavaScript — control flow, concurrency, and data flow included.

    
                    

    get started

    From install to first run in three files

    AML is under active development. These examples show the intended API shape and may differ from the current implementation.

    step 1

    Install the runtime

    $ npm install @aml-jsx/sdk

    Coding with an agent?

    $ npx skills add we-are-singular/aml --skill aml-jsx

    step 2

    Point JSX at AML

    {
      "compilerOptions": {
        "jsx": "react-jsx",
        "jsxImportSource": "@aml-jsx/sdk"
      }
    }

    step 3

    Evaluate a tree

    import { Agent, AmlRuntime, opencodeAgent } from "@aml-jsx/sdk"
    
    const OpenCode = opencodeAgent({})
    const runtime = new AmlRuntime()
    await runtime.evaluate(
      <Agent provider={OpenCode}>Summarize this repository.</Agent>,
    )

    contributing

    AML is early. Help shape what it becomes.

    Want to build a provider, sharpen the runtime semantics, improve the developer experience, or argue for a better API? This is the useful stage to show up: the important decisions are still being made.

    help create provider adapters · shape the runtime · improve examples, docs, and tooling

    Help build AML