v4 — preview release

Web automation that learns the site,
then runs it deterministically.

A3 is a stage-based automation framework. You define the workflow and any agents; A3 learns and writes typed stage modules plus a durable playbook, and the runner replays them with no LLM in the loop.

npm i @athree/runner @athree/cli
— What it is

Three runtimes, one mental model.

A3 separates the parts of automation that benefit from intelligence from the parts that don't. You define the workflow and agents once. Stages are then learned and captured as code. A runner replays them — fast, typed, and free of model spend.

01 · WORKFLOW

Set the objective and mission.

You start by defining the objective, then writing a clear mission file that describes what success looks like.

mission.md
02 · CONFIG

Provide tools and workflow config.

You define the tools, schemas, and configuration in the workflow so the agent has strict contracts while learning.

defineWorkflow()
03 · AGENT

Agent learns each target site.

The agent visits each target website and creates per-page stages as readable Playwright scripts.

Learning
04 · PLAYBOOK

Findings are captured in markdown.

The agent writes findings to playbook.md, making edge-case fixes and future site changes easy to handle.

playbook.md
05 · FILES

Everything is plain files.

Stages, playbooks, and config live as directly editable files inside your git repo.

git-friendly
06 · RUNNER

Run at scale, low cost.

Automations run at scale on UBIO Automation Cloud with no LLM required at runtime.

a3 run / cloud
— Works for any use case

Same 6 steps, different automation goals.

Select a use case to preview how A3 applies the same six-step model in practice. Then look below to see fully worked Step 1-6 examples update instantly for that scenario.

Hotel rates scraping

— Steps 1-2 · User

User defines mission and configuration.

  • Step 1 (User): set the objective and write mission.md.
  • Step 2 (User): provide tools and workflow config so the agent has strict boundaries during learning.
Step 1 · User: mission Configuration
objectives/mission.md
# Mission — scrape rates

Given a hotel id, stay dates, and guest count, drive the property’s booking flow on the live site.
Prefer the public consumer path unless `playbook.md` already documents otherwise.

## What to capture

- Every bookable room with nightly rates (fees/taxes when the UI shows them).
- Normalise to the workflow’s `Rate` schema — don’t invent inventory the page never offered.
Step 2 · User: workflow config Configuration
scrape-rates.workflow.ts
import { defineWorkflow } from '@athree/runner';
import { ScrapeRatesInputSchema } from './schema/ScrapeRatesInput.js';
import { ScrapeRatesOutputSchema } from './schema/ScrapeRatesOutput.js';
import { TestAgent } from './TestAgent.js';

export default defineWorkflow({
  title: 'Scrape Rates',
  description: 'Scrape rates from a website',
  inputsSchema: ScrapeRatesInputSchema,
  outputsSchema: ScrapeRatesOutputSchema,
  rootDir: 'src',
  sitesDir: import.meta.dirname + '/sites',
  agents: [TestAgent],
  projectLocations: [
    { dir: import.meta.dirname + '/objectives',
      writable: true, patterns: ['*.md'] },
    { dir: import.meta.dirname + '/schema',
      writable: false },
  ],
});
— Steps 3-4 · Agent

Agent learns sites and documents findings.

  • Step 3 (Agent): visit each target website and generate readable stage files under sites/<hostname>/.
  • Step 4 (Agent): write findings into playbook.md, including drift and edge-case notes in the changelog.
Step 3 · Agent output: stage Learning output
sites/be-synxis-com/extract-rates.stage.ts
import { defineStage } from '@athree/runner';

export default defineStage({
  title: 'Extract Rooms and Rates',
  description: 'Pulls rooms+rates from API or DOM',
  success: true,
  match: async (ctx) => {
    const url = new URL(ctx.page.url());
    return url.pathname.startsWith('/');
  },
  run: async (ctx) => {
    const resp = ctx.networkResources.find(
      r => r.request.url.includes('getProductAvailability')
    );
    const data = JSON.parse(resp.response.responseBody);
    ctx.outputs.hotelId = ctx.inputs.search.hotelId;
    ctx.outputs.results = [{ search: ctx.inputs.search,
                             rooms: extract(data) }];
  },
});
Step 4 · Agent output: playbook Learning output
sites/be-synxis-com/playbook.md
# Synxis property — public rates

## Objective
Scrape nightly room rates from the consumer booking path.

## Entry points
- Deep link with property id + stay dates, or hotel home → check availability.

## Flow states
1. `cookie-banner` (dismiss)
2. `rate-shopping` (rates visible)

## Known risks
- Inventory JSON from `getProductAvailability`; vendor changes the shape occasionally.

## Changelog

### 2026-04-12
- Rates list moved to `[data-test="room-list"]`; `extract-rates` `match()` updated. Mobile lazy-loads guest row — `main.stage.ts` waits on `networkidle`.

### 2026-01-28
- Currency toggle removed; property currency only. “Member rate” badge ignored for the public `Rate` schema.
— Steps 5-6 · User + Infrastructure

User-owned files, infrastructure-scale runs.

  • Step 5 (User): all artifacts are editable files in git.
  • Step 6 (Infrastructure): the same files run deterministically at scale, with no LLM required during runtime.
Step 5 · User-owned project files Configuration
my-automation-project/
├── package.json
└── src/
    └── workflows/scrape-rates/
        ├── scrape-rates.workflow.ts
        ├── TestAgent.ts
        ├── objectives/
        │   └── mission.md
        ├── schema/
        │   ├── ScrapeRatesInput.ts
        │   ├── ScrapeRatesOutput.ts
        │   └── Rate.ts
        ├── skills/
        │   └── create-site/SKILL.md
        └── sites/
            ├── default/
            │   └── main.stage.ts          # global fallback
            ├── be-synxis-com/
            │   ├── main.stage.ts
            │   ├── extract-rates.stage.ts
            │   ├── inputs.yaml
            │   └── playbook.md
            └── asp-hotel-story-ne-jp/
                ├── main.stage.ts
                ├── inputs.yaml
                └── playbook.md
Step 6 · Infrastructure runtime config Infrastructure
infra/ubio-runner.yaml
version: '1'
workflow: src/workflows/scrape-rates/scrape-rates.workflow.ts
runtime:
  provider: ubio-automation-cloud
  mode: deterministic
  llmInLoop: false
  concurrency: 60
  retries:
    maxAttempts: 2
    backoffMs: 1500
targets:
  - site: be-synxis-com
    inputs: src/workflows/scrape-rates/sites/be-synxis-com/inputs.yaml
  - site: asp-hotel-story-ne-jp
    inputs: src/workflows/scrape-rates/sites/asp-hotel-story-ne-jp/inputs.yaml
outputs:
  artifactDir: ./.runs/scrape-rates
  uploadPlaybooks: true
— Get started

Start building your first workflow in minutes.

Begin with the quickstart in Docs, learn the architecture in Concepts, and use API reference pages while implementing workflows and stages.