Skip to content

Latest commit

 

History

339 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agent Markup Language

image

Agent Markup Language (AML) is a TypeScript framework for building AI agents and multi-agent applications with JSX.

Compose an agent's instructions and tools as reusable components, feed one agent's result into another, and run independent specialists in parallel. AML manages their sessions, limits, cancellation, and resource cleanup. Your TypeScript code owns decisions and validation; built-in providers connect to existing coding agents that keep their native model loops and tools.

Build code reviewers, support agents, research workflows, or automation that works on files. Start with one Agent and add a Sandbox for execution or a Workspace for durable files when the task needs them.

Get started · Examples · API reference

AML is under active development. Public package APIs and examples may change before the first stable release.

Why AML

Agent SDKs are good at running one provider session. Real workflows usually need more: parallel specialists, ordered synthesis, shared context, custom JavaScript tools, model-specific adapters, sandbox boundaries, durable files, follow-up turns, and useful traces.

Without a shared runtime, those concerns become orchestration code tied to one provider. AML keeps the workflow declarative and uses the Agent Client Protocol (ACP) as the canonical session boundary for built-in coding agents.

Each <Agent /> runs after its child results and capabilities resolve. When the workflow includes a Workspace and Sandbox, AML materializes the files before running the sandboxed Agent. Revision-backed Workspaces publish only when saving is enabled; a local Workspace uses its existing directory directly. The selected Sandbox provider owns process execution and its actual isolation guarantees.

AML tree
  ├─ resolve components and context
  ├─ acquire Workspace and Sandbox resources
  ├─ run independent Agents through injected providers
  ├─ carry their results into parent prompts
  └─ release resources and return the final output

Ordinary JSX children resolve in authored order. Wrap independent AML branches in <Parallel> when their text should flow directly into the surrounding tree. Component code can still use Promise.all(evaluate(...)) when it needs named or typed branch values.

Quick start

Use Node.js 26 or newer and an ESM project ("type": "module" in package.json). Install the SDK and a TSX runner:

npm install @aml-jsx/sdk
npm install --save-dev typescript vite-node

Configure TypeScript to use AML's automatic JSX runtime:

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

Save this as workflow.tsx:

import { Agent, AmlRuntime } from "@aml-jsx/sdk"
import { DeterministicAgentProvider } from "@aml-jsx/sdk/testing"

const runtime = new AmlRuntime({ agentProvider: new DeterministicAgentProvider() })
console.log(await runtime.evaluate(<Agent>Hello from AML.</Agent>))

Run npx vite-node workflow.tsx. It prints Hello from AML. without credentials or a model. The tutorial continues with a reusable agent team and live-provider setup.

Example: a code-review team

This live example assumes a project containing src/index.ts, zod installed separately, and an authenticated OpenCode provider. It composes Agents and a typed JavaScript Tool:

import { readFile } from "node:fs/promises"

import { Agent, AmlRuntime, createConsoleTracer, defineTool, opencodeAgent, Parallel, Tool } from "@aml-jsx/sdk"
import { z } from "zod"

const OpenCode = opencodeAgent({})

const ReadSource = defineTool({
  name: "read_source",
  description: "Read one source file from the current project",
  input: z.object({ path: z.literal("src/index.ts") }),
  execute: async ({ path }) => await readFile(path, "utf8"),
})

function CorrectnessLane() {
  return (
    <>
      Correctness:
      <Agent provider={OpenCode} system="Find concrete correctness defects.">
        <Tool use={ReadSource} />
        Review src/index.ts.
      </Agent>
    </>
  )
}

function MaintainabilityLane() {
  return (
    <>
      Maintainability:
      <Agent provider={OpenCode} system="Find proportionate maintainability improvements.">
        <Tool use={ReadSource} />
        Review src/index.ts.
      </Agent>
    </>
  )
}

function Review() {
  return (
    <Agent provider={OpenCode} system="Synthesize evidence without inventing findings.">
      <Parallel>
        <CorrectnessLane />
        <MaintainabilityLane />
      </Parallel>
    </Agent>
  )
}

const runtime = new AmlRuntime()
runtime.on("trace", createConsoleTracer())

console.log(await runtime.evaluate(<Review />))

defineTool() returns a typed callable. An active function component can call ReadSource({ path }) as application work, while <Tool use={ReadSource} /> explicitly grants that same Tool to one model session.

The workflow stays the same when the provider changes. Replace OpenCode with a Codex, GitHub Copilot, GLM, or Pi provider without rewriting the AML tree:

import { piAgent } from "@aml-jsx/sdk"

const Pi = piAgent({
  env: { OPENCODE_API_KEY: process.env.OPENCODE_API_KEY ?? "" },
  model: "opencode-go/deepseek-v4-flash",
})

Codex, GitHub Copilot, GLM, OpenCode, and Pi use compatible ACP Agent executables. Their normal public factories are thin profiles over one shared session engine, so changing the provider does not select a different local-versus-Sandbox lifecycle. GLM uses the community-maintained glm-acp-agent adapter, not Z.ai's ZCode harness. The selected host, image, snapshot, or package set must contain the compatible executable; AML does not install Agents implicitly.

Coding agents

Install the repository's aml-jsx skill to give supported coding agents the current AML authoring patterns, runtime semantics, provider guidance, and testing conventions:

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

The command installs the skill into the current project. Add -g to make it available globally. The skill is stored in skills/aml-jsx and should be used whenever an agent builds, explains, tests, or debugs workflows with @aml-jsx/sdk. This is an explicit developer installation step, not runtime registry access by AML's <Skill> component.

Primitives

Primitive Purpose
<Agent> Runs one Agent session and optionally validates its result with an Agent-owned schema.
<Parallel> Evaluates independent AML branches concurrently, then contributes their text in authored order.
<Block> Adds exact blank-line separation and optional kebab-cased section tags without creating a new runtime scope.
<Include> Reads an application file or active-filesystem path into a prompt, with bounded inline content.
<System> Adds resolved content to the owning Agent's system prompt. Multiple System blocks are joined in authored order.
<Tool> Grants the owning Agent a JavaScript Tool created with defineTool().
<Skill> Stages and registers a complete local Agent Skill package for one Agent session.
<File> Writes a local source or resolved text through the nearest Workspace or Sandbox filesystem.
<Mcp> Grants the owning Agent a provider-native MCP server by name or an explicit server created with defineMcpServer().
<FollowUp> Adds a later turn to the same Agent session. FollowUps are flat, ordered, and resolved before the session starts.
<Sandbox> Acquires an ephemeral execution environment and scopes a narrowed filesystem policy to descendant Agents.
<Script> Executes resolved source or one literal command on the host or in the active Sandbox and returns standard output.
<Workspace> Materializes durable files that can survive and be shared across disposable Sandbox leases.
<>...</> Groups AML values without adding prompt text or another runtime boundary.

Prompt files and Agent Skills are deliberately separate:

<Workspace provider={workspace}>
  <File path="brief.md">Review the authentication boundary.</File>
  <Sandbox provider={sandbox} access="read-write">
    <Agent>
      <Skill src="./skills/code-review" />
      <Block tag="review-brief">
        <Include path="brief.md" maxBytes={4_000} />
      </Block>
      Complete the review.
    </Agent>
  </Sandbox>
</Workspace>

<Include src> reads an application-owned UTF-8 file from the runtime cwd. <Include path> reads a UTF-8 file from the nearest filesystem. AML caches unchanged revisions with bounded content retention. Oversized application sources and host-Workspace paths are staged automatically at an Agent-visible path, while active Sandbox paths remain live and are referenced from the effective Agent cwd; the prompt reports the authored path, size, and line count before that read instruction. <Skill src> expects a local package directory containing SKILL.md; AML materializes the full package under the .agents/skills/<name>/ suffix of a writable Agent staging root, uses native provider discovery when available, and otherwise emits only discovery metadata containing the concrete path. AML does not fetch or install remote Skill packages.

Core APIs

API Purpose
AmlRuntime Evaluates a complete AML tree, owns budgets and lifecycle events, and returns the final text output.
ProcessSignalCancellation Converts application-owned SIGINT/SIGTERM handling into bounded runtime cancellation.
evaluate() Evaluates AML from inside an active component and returns text or schema-validated structured data.
defineTool() Creates a typed callable Tool for application code or an explicit <Tool use> model grant.
defineMcpServer() Creates an immutable provider-neutral MCP descriptor for a local stdio process or remote Streamable HTTP server.
defineAgentProvider() Defines an Agent harness adapter implementing AML's provider contract.
AbstractAgentProvider Optional lifecycle template for custom structural providers outside the built-in ACP path.
AgentProviderSession Narrow invocation session available to custom providers using that lifecycle template.
createAgentProviderTurns() Validates and captures ordered initial and FollowUp turns for a provider session.
executeAgentProviderSession() Executes a captured session with shared cancellation, result selection, and cleanup semantics.
defineSandboxProvider() Defines an ephemeral execution provider.
AbstractSandboxProvider Optional template for staged Sandbox provisioning, initialization, compensation, and release.
ProvisionedSandbox Acknowledged provider resource used by the Sandbox lifecycle template for compensation and release.
SandboxCommand Captures and validates one portable literal Sandbox command before backend translation.
defineWorkspaceProvider() Defines a durable filesystem materialization provider.
createPersistentWorkspaceProvider() Builds revision persistence over a user-defined WorkspaceStorageAdapter.
runtime.on() / runtime.once() Subscribes to evaluation lifecycle and trace events.
withTraceSpan() Measures application-owned work inside the active function component.
createTraceSummaryCollector() Derives run-keyed, content-free summaries from the public trace stream.

Application observability

AML automatically traces function components and runtime primitives, but a component span covers both the component call and resolution of its returned subtree. It cannot identify an application phase inside that component, such as validation, retrieval, or persistence. Use withTraceSpan() for that real lexical work:

async function Review({ findings }: { findings: readonly Finding[] }) {
  return await withTraceSpan("review.validate", async () => await validateFindings(findings))
}

Application spans inherit the active component or application-span parent, close on success, error, or cancellation, and preserve the callback's result or thrown value. Calls outside an active function component, including detached work after it settles, are rejected. AML retains allocation of runId, spanId, and ancestry; applications supply only the span name and work to measure.

createTraceSummaryCollector() consumes the same public immutable events as any other sink. Summaries are retrieved by explicit runId, so runtime reuse and overlapping evaluations never depend on a global latest result. They include evaluation status and wall duration, Agent session and turn timing, Tool and resource timing, named application spans, ACP tool-call counts, raw provider-reported usage entries, and Agent cleanup outcomes. acpToolCalls counts initial ACP tool_call updates and groups them by exact provider-reported capability name. Those names do not portably identify the backend or MCP server that handled a call. The separate tools aggregate measures declarative AML <Tool> execution spans, so one call routed to an AML Tool may correctly appear in both; AML does not deduplicate the distinct boundaries. Trace-consumer failures remain on the runtime's existing onTraceError channel. An empty providerUsage means the provider reported no usage; AML does not infer model-call counts, token fields, cache behavior, cost, or billing data. Each timing aggregate reports count, summed totalDurationMs, and slowestMs when present. Completed summaries remain available until the application calls deleteRun(runId).

See the production-oriented observability cookbook for custom phase timing, request-to-run correlation across concurrent evaluations, optional usage, cleanup, and trace-consumer reporting.

Experimental APIs

<Loop>, <Context.Provider>, createContext(), and useContext() are implemented and exported for evaluation, but they are not yet stable release-ready contracts. They may change while their semantics are being evaluated.

Providers

The public SDK includes the runtime, built-in integrations, and testing utilities under one package.

Role Source Public export Notes
Agent OpenCode adapter opencodeAgent() OpenCode ACP profile with model/system mapping and native capability metadata.
Agent Codex adapter codexAgent() Codex ACP profile using the maintained Codex ACP adapter.
Agent Copilot adapter copilotAgent() GitHub Copilot CLI profile using its native ACP server and invocation-private Copilot state.
Agent GLM adapter glmAgent() Community glm-acp-agent profile for Z.ai Coding Plan models; this is not the ZCode harness.
Agent Pi adapter piAgent() Pi ACP profile using the maintained Pi ACP adapter.
Sandbox Local adapter localSandbox() Runs the common Sandbox runtime as trusted host processes for development; it is explicitly non-isolating.
Sandbox Docker adapter dockerSandbox() Starts AML's default Agent image or an override, mounts the Workspace, and exposes the common bounded command runtime without building the image.
Sandbox Daytona adapter daytonaSandbox() Creates AML's default Agent image or an explicit Daytona image/snapshot, transfers the Workspace, reconciles writable changes, and deletes the remote Sandbox.
Sandbox Modal adapter modalSandbox() Creates a Modal Sandbox from AML's default Agent image or a registry override, transfers the Workspace, reconciles writable changes, and terminates it.
Workspace Local adapter localWorkspace() Uses an existing local directory as a durable Workspace with cross-process writer locking.
Workspace Local adapter filesystemWorkspace() Stages archive or folder revisions from a durable local filesystem store into a safe temporary materialization.
Workspace S3 adapter s3Workspace() Restores and publishes immutable archive or folder revisions through S3-compatible storage. R2 has repository smoke evidence; other backends require deployment-specific compatibility verification.
Testing Testing entry @aml-jsx/sdk/testing Supplies deterministic Agent, Sandbox, and Workspace providers plus reusable conformance suites.

Docker, Daytona, and Modal default to the full wearesingular/aml-agent-sandbox:latest image. Stable Docker Hub releases also publish matching codex, copilot, glm, opencode, and pi variants, while ghcr.io/we-are-singular/aml-agent-sandbox:dev remains the mutable full image built from main. See AML Agent Sandbox images for contents, registry links, tags, selection, pinning, and extension.

The credentialed smoke runner exercises the complete built-in Agent × Sandbox matrix:

Sandbox \ Agent Codex Copilot GLM OpenCode Pi
Local Yes Yes Yes Yes Yes
Docker Yes Yes Yes Yes Yes
Daytona Yes Yes Yes Yes Yes
Modal Yes Yes Yes Yes Yes

Every cell launches its Agent through the same shared ACP engine and SandboxRuntime.spawn(). Sandbox runtimes also expose portable stat, complete-file read, and atomic replacement write operations used by File, Include, and Agent staging. These proofs use read-write Workspaces where a provider cannot enforce read-only access. The selected host, image, or snapshot must contain the required executable. Sandbox providers do not install Agents implicitly.

Docker, Daytona, and Modal smoke cells use the full GHCR dev image. Set AML_SMOKE_SANDBOX_IMAGE to run every image-backed cell against one explicit reference, such as an immutable version or digest.

<System>, <Include>, <Skill>, <FollowUp>, Context, Agent staging, and tree evaluation are runtime-owned. <Block> is a transparent authoring component with exact separator output and optional XML-style section tags. JavaScript Tools use one AML-owned invocation MCP bridge. Structured output uses one AML-owned submission Tool on the final authored turn and one shared, schema-bearing repair prompt if that turn omits the Tool call. Agent permissions default to read-write filesystem, shell, and network access; the active Sandbox remains the security boundary for model-controlled operations.

Provider factories retain typed vendor configuration and process environment inputs. Credentials normally remain in the selected host or Sandbox environment; an application may also pass explicit invocation environment variables without changing the AML tree.

Sandbox factories keep environment identity at the factory root: Docker and Modal accept an optional image, while Daytona accepts either image or snapshot. Omitting those selectors uses wearesingular/aml-agent-sandbox:latest. Daytona's create retains its remaining image- or snapshot-specific creation parameters, and Modal's create retains its native Sandbox creation options. AML does not build images or silently install Agents. Each Sandbox may run an explicit trusted setup command after its Workspace is visible.

The S3 Workspace factory accepts an injected S3Client or its native client configuration. A local MinIO instance uses the same provider with an endpoint and path-style addressing:

const workspace = s3Workspace({
  bucket: "aml-workspaces",
  config: {
    credentials: {
      accessKeyId: "aml-minio",
      secretAccessKey: "aml-minio-secret",
    },
    endpoint: "http://127.0.0.1:19000",
    forcePathStyle: true,
    region: "us-east-1",
  },
})

Each revision-backed Workspace identity has an atomic workspace.json index and immutable revisions. lock defaults to true, so one evaluation owns that identity until save and release; built-in locks use a fixed five-minute heartbeat and become recoverable after twenty minutes without renewal. lock={false} permits concurrent materializations, while conditional index publication prevents a stale save from overwriting committed state. format is "archive" | "folder" and defaults to archive. The shared persistence engine—not the S3 or filesystem adapter—owns selection, .gitignore, tar handling, folder manifests, retention, and revision publication.

File can turn a child Agent result into a durable handoff without duplicating that text into the surrounding prompt. An unsandboxed Script runs as a trusted host process from the runtime cwd. Its optional portable cwd resolves from that runtime cwd; inside a Sandbox it resolves from the active Sandbox root. Workspace supplies the default logical cwd for descendant Sandboxes, and a Script inside one always uses that Sandbox runtime:

const status = await new AmlRuntime().evaluate(<Script cwd="apps/cli" command="git" args={["status", "--short"]} />)
<Workspace
  cwd="repo"
  id="review-42"
  load={{ revision: "current" }}
  lock
  provider={workspace}
  save={{
    include: ["repo/src/**", "repo/tests/**", "report.md"],
    exclude: ["**/node_modules/**"],
  }}
  writeConcurrency="serial"
>
  <File path="task.md">
    <Agent provider={planner}>Write a focused implementation task.</Agent>
  </File>

  <Sandbox access="read-write" provider={sandbox}>
    <Script command="git" args={["status", "--short"]} />

    <Script shell="node">{`import { writeFileSync } from "node:fs"; writeFileSync("ready.txt", "yes")`}</Script>

    <Agent provider={builder}>
      <Include path="task.md" maxBytes={8_000} />
      Implement the task and write report.md.
    </Agent>
  </Sandbox>
</Workspace>

id defaults to crypto.randomUUID(), cwd and current-revision loading default to "." and enabled respectively, locking defaults to enabled, writable Sandbox concurrency defaults to "serial", and saving defaults to disabled. Serial mode waits before acquiring another writable root Sandbox, so transferred Sandboxes hydrate only after the previous writer reconciles. Read-only Sandboxes and agents sharing one Sandbox can still run concurrently. writeConcurrency="parallel" is intended for shared mounts; transferred snapshots can overwrite one another. save: true discovers the tree subject to .gitignore, publishes after success, and retains one revision. Explicit include patterns override .gitignore; excludes always win. save={{ on: "always" }} also publishes failed work, while cancellation never saves.

Examples

Every example is one self-contained AML component. Run one with npm run example -- <name>.

Example Description
basic Resolves ordinary synchronous and asynchronous JSX components from the leaves upward.
component-types Types leaf and async components, optional children, and required children with the type-only AML namespace.
agent Uses a child Agent to generate System content for its parent.
concurrency Runs two specialists concurrently and preserves authored result order for synthesis.
structured Passes schema-validated Agent data into a later text-producing Agent.
context Injects a session repository and captures it inside a JavaScript Tool without adding it to the prompt.
programmatic-tool Calls a validated Tool from application component code without granting it to a model.
follow-up Authors several turns inside one Agent session.
skill Stages a complete local Agent Skill package for progressive discovery.
mcp Grants one Agent an MCP server while proving sibling capability isolation.
sandbox Narrows nested Sandbox access while sharing one deterministic outer lease.
script Selects a Script working directory relative to the active Sandbox root.
workspace Shares one durable materialization across disposable Sandbox leases.
opencode Uses a credentialed OpenCode model to call a process-local JavaScript Tool.
pi Embeds Pi with an OpenCode Go model and calls a process-local JavaScript Tool.
review Runs a parallel multi-agent code review through deterministic, OpenCode, or Codex providers.
docker Inspects a real Docker Sandbox's working directory and confinement settings.
modal Inspects a real Modal Sandbox through the common bounded runtime.
workspace-local Persists a file across disposable Sandbox runs through the local Workspace provider.
workspace-routing Uses typed Agent output to select a local Workspace and pass a normalized task to a second Agent.

The deterministic examples are snapshot-tested. Live model, Docker, and filesystem integrations are opt-in.

Repository layout

sdk/        @aml-jsx/sdk, the AML runtime and public API
providers/  optional Agent, Sandbox, and Workspace provider implementations
apps/       runnable products built on AML (website: the project site)
examples/   human-readable client workflows

SPEC.md is the normative behavior contract. PRD.md records product decisions, architecture, and delivery status. PROVIDERS.md tracks the provider implementation wishlist.

Development

Requirements:

  • Node.js 26 or newer
  • npm 11 or newer
  • Docker for Docker integration tests, examples, and the local MinIO integration
  • Configured Codex, GitHub Copilot, GLM, OpenCode, or Pi-supported model-provider credentials only for live Agent examples

Install dependencies:

npm install

Common commands:

Command Purpose
npm run format Format supported repository files with Oxfmt.
npm run format:check Verify formatting without changing files.
npm run lint Type-check and lint every workspace.
npm run test Run deterministic tests across every workspace.
npm run build Build every distributable package.
npm run pack:check Validate built exports, packed files, and provider conformance.
npm run example -- basic Run one example through built package exports.
npm run example -- review Run the review workflow with its deterministic provider.
AML_REVIEW_PROVIDER=opencode npm run example -- review Run the review workflow through OpenCode.
AML_REVIEW_PROVIDER=codex npm run example -- review Run the review workflow through Codex.
npm run example -- pi Run Pi through its ACP adapter and configured credentials.
npm run example -- docker Run the real Docker Sandbox example.
npm run smoke -- --agent pi --sandbox daytona Run one Agent × Sandbox smoke matrix cell with live traces.
npm run smoke -- --agent codex Run one Agent against every registered Sandbox.
npm run smoke -- --sandbox docker Run every registered Agent against one Sandbox.
npm run smoke:kitchen-sink Run all stable primitives through R2, OpenCode, and Modal.
npx vite-node sdk/tests/smoke/workspace-s3-chain.smoke.tsx Run the Docker → Daytona → S3 Workspace persistence proof.
npm run test:integration --workspace=@aml-jsx/sandbox-modal Run Modal's credentialed Workspace round-trip proof.
npm run smoke -- --list List the complete or filtered matrix without executing it.

Package-specific integration suites are available through their workspace scripts:

npm run test:integration --workspace=@aml-jsx/agent-opencode
npm run test:integration --workspace=@aml-jsx/agent-codex
npm run test:integration --workspace=@aml-jsx/agent-glm
npm run test:integration --workspace=@aml-jsx/agent-pi
npm run test:integration --workspace=@aml-jsx/sandbox-docker
docker compose up -d --wait minio
npm run test:integration --workspace=@aml-jsx/workspace-s3
docker compose down

Smoke tests

Matrix smoke files use a dedicated Vitest configuration and stay outside default unit tests. Omitting both matrix filters runs every registered Agent against every registered Sandbox. npm requires the -- separator before smoke-runner options.

The manual kitchen-sink smoke defaults to --agent opencode --sandbox modal --workspace r2 --mcp context7. It accepts any registered Agent or Sandbox, plus local | r2 Workspaces and context7 | none MCP selection. The workflow exercises all fourteen stable primitives, then reacquires the saved Workspace and verifies the persisted files. Run npm run smoke:kitchen-sink -- --help for the current selections. Context7 supports anonymous testing; CONTEXT7_API_KEY raises its rate limit when configured.

The smoke runners load the repository's untracked .env. Codex uses OPENAI_API_KEY or AML_CODEX_API_KEY and defaults to gpt-5.6-luna with low reasoning effort. OpenCode and Pi use OPENCODE_API_KEY and default to opencode-go/deepseek-v4-flash. AML_CODEX_MODEL, AML_OPENCODE_MODEL, and AML_PI_MODEL may override those models. Copilot uses COPILOT_GITHUB_TOKEN, GH_TOKEN, or GITHUB_TOKEN in that order and defaults to gpt-5-mini; AML_COPILOT_GITHUB_TOKEN and AML_COPILOT_MODEL are optional smoke-only overrides. GLM uses Z_AI_API_KEY or AML_ZAI_API_KEY and defaults to glm-5.3; AML_GLM_MODEL may override its model. Daytona uses DAYTONA_API_KEY. Modal uses the repository-local MODAL_API_KEY and MODAL_API_SECRET names as tokenId and tokenSecret; Modal's own ambient credential names remain MODAL_TOKEN_ID and MODAL_TOKEN_SECRET. The R2 Workspace accepts R2_BUCKET, R2_ENDPOINT, R2_ACCESS_KEY_ID, and R2_SECRET_ACCESS_KEY, with the existing AML_S3_* aliases. These environment names configure only the repository's smoke CLI. Applications configure providers through their native factory options and runtime environment.

The full matrix and the default kitchen sink are manual release gates. Run both before every package release, and always before a major-version release:

npm run smoke
npm run smoke:kitchen-sink

They intentionally stay outside CI and npm run release:check because they consume paid model inference and may provision billable remote Sandbox and Workspace infrastructure. A green deterministic CI run does not replace these live compatibility and composition proofs.

Commits are checked with lint-staged and commitlint. Pushes run the same formatting, linting, test, and build contract enforced by GitHub Actions.

Releasing

SDK, CLI, and image releases are manual and independent. Complete the manual smoke tests, start from a clean main that matches origin/main, authenticate with the required registries and GitHub, then run the interactive release for the intended package:

npm login
GITHUB_TOKEN="$(gh auth token)" npm run release:sdk
GITHUB_TOKEN="$(gh auth token)" npm run release:cli
npm run release:sandbox

npm run release remains an alias for release:sdk. Release It runs the release checks, prompts for the next version, updates the selected package and lockfile, pushes the release, and creates the matching GitHub release. SDK and CLI releases publish to npm and use vX.Y.Z and cli-vX.Y.Z tags. Stable Sandbox releases publish full and single-Agent variants to Docker Hub under one sandbox-vX.Y.Z source tag. Publication runs each Agent's real Docker smoke against its pushed variant before signing its digest and updating moving tags. npm prompts for OTP or passkey approval when required. Stable image publication uses a temporary Docker Hub browser login and a local Cosign installation. The active GitHub CLI account creates the source release. GitHub Actions separately publishes the full GHCR dev image after relevant changes reach main.

Release notes follow those package lanes instead of including every repository commit. CLI notes include commits scoped to cli. SDK notes include commits scoped to sdk or an SDK-owned runtime, primitive, Agent, Sandbox, Workspace, or provider area. Website, examples, root maintenance, and unscoped commits stay out of package release notes.

The release gate fetches and verifies the upstream branch before versioning. After the version and lockfile are bumped, it runs the complete release checks again before npm publishing. Push and verify source commits first; the release flow then owns only its version commit, package tag, npm publication, and GitHub release.

Preview the flow without changing Git, npm, or GitHub:

GITHUB_TOKEN="$(gh auth token)" npm run release:sdk -- --dry-run
GITHUB_TOKEN="$(gh auth token)" npm run release:cli -- --dry-run
npm run release:sandbox -- --dry-run

If registry publication fails after the release commit and sandbox-vX.Y.Z tag are created, rerun that exact release from a clean main checkout with npm run release:sandbox -- --recover.

The Astro website and Starlight documentation run locally at http://localhost:5321/ from the repository root:

npm run dev

Run the command from the repository root. An uv_cwd or process.cwd ENOENT means the shell is still attached to a directory that was moved or removed; open a new shell or cd /path/to/agent-markup-language before invoking npm.

The project site and documentation are one static Astro application:

apps/website/src/
  pages/index.astro             marketing route composition
  layouts/MarketingLayout.astro
  components/marketing/        reusable homepage sections
  data/                        typed navigation, provider, and homepage content
  content/docs/                Starlight documentation source
  components/docs/             shared Starlight layout, provider, and page-action UI
  plugins/docs-markdown/        injected /[...path].md endpoint (per-page Markdown alternatives)
  pages/docs/llms.txt.ts        complete concatenated documentation
  styles/                      global Starlight layout and content rhythm

The public routes are intentionally available to both people and agents:

Route Purpose
/ Marketing and project overview.
/docs/ and /docs/** Navigable Starlight documentation.
/docs.md Markdown alternative for the documentation homepage.
/docs/<page>.md Markdown alternative linked from every documentation page.
/llms.txt Concise project and editorial overview.
/docs/llms.txt Complete documentation in one text response.
/robots.txt, /sitemap.xml Search crawler discovery; Markdown alternatives stay canonical.

Marketing metadata is centralized in src/config/site.ts. Starlight extends its generated metadata through components/docs/DocHead.astro, which adds the share image, Markdown alternate, complete-docs discovery link, and structured data. Keep layout or typography changes in the shared layouts and global styles rather than individual content pages.

Pushes to main deploy apps/website/dist to GitHub Pages at agent-markup-language.com. The generated directory is ignored and uploaded directly by GitHub Actions; it is not committed to a publishing branch.

License

AML is available under the MIT License.

About

Agent Markup Language - an asynchronous TypeScript and JSX runtime for composing provider-agnostic agent workflows.

Topics

Resources

Stars

13 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages