Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Meza-dev/Ghostly/llms.txt

Use this file to discover all available pages before exploring further.

In standard mode you write every step yourself — goto, click, fill, and so on. Assisted mode flips this around: you describe what you want the browser to accomplish in plain English, and Ghostly’s AI pipeline plans and executes the steps on your behalf. The AI observes the live page after every action, adapts its plan when something unexpected appears, and keeps running until it achieves your stated goal or hits a configurable time/horizon limit.

Two Generations of Assisted Mode

Ghostly has shipped two versions of the assisted pipeline. Only v2 is actively developed and recommended for new projects.
v1v2
Planning strategySingle-shot: generate all steps upfrontHorizon-based: plan a small batch, execute, observe, repeat
AdaptationNone — plan is fixedRe-plans after failures; evaluates victory after each horizon
Self-healingNoYes — up to maxHealingAttemptsPerStep per step
MemoryNoYes — adaptive, runtime, or off
Fieldassisted metadata onlyassist.v2: true with full config object

How v2 Works: The Horizon Loop

The v2 pipeline is a loop that alternates between planning and executing phases, called horizons. Each horizon covers a small window of steps determined by stepsPerHorizon.
1

Initial Recon

Ghostly navigates to baseUrl and captures the page’s accessibility tree via the Observer. This snapshot — URL, page title, visible controls, form inputs, and dialog state — is sent to the Strategist as context. A recon event is emitted.
2

Plan a Horizon

The Strategist (an LLM-backed function) receives the goal, the current snapshot, the execution history so far, and the victory conditions. It returns up to stepsPerHorizon steps as a PlannedChunk. Ghostly emits a plan_chunk event.
3

Execute Steps

Each step in the horizon is run one by one using Playwright. After each successful step, the Observer captures a fresh snapshot. If a step fails and maxHealingAttemptsPerStep > 0, the Healer agent attempts to recover it before moving on.
4

Check Victory

After every step (and again at the end of each horizon), Ghostly evaluates the configured victory conditions against the current URL, page text, and visible selectors. If all configured conditions are met, the run is marked pass and the loop exits.
5

Next Horizon or Stop

If victory is not yet achieved, Ghostly increments the horizon counter and returns to the planning phase with the updated snapshot and history. The loop exits when victoryMet, maxHorizons is reached, or maxLoopMs is exceeded.

Victory Conditions

Victory conditions tell Ghostly when to stop and declare success. They are evaluated after every executed step and at the end of each horizon.
// From packages/runner/src/assist/types.ts

export type VictoryCondition = {
  textIncludes?: string[];     // Page text must contain these strings
  selectorVisible?: string[];  // These CSS selectors must be visible
  urlIncludes?: string[];      // Current URL must contain these strings
  mustAll?: boolean;           // true = all checks must pass (AND); false = any (OR)
};

textIncludes

The page body, title, or accessibility tree must contain each supplied string (case-insensitive).

selectorVisible

Each CSS selector (or natural-language phrase) must resolve to a visible element. Supports Playwright selectors and plain text descriptions.

urlIncludes

The current page URL must contain each string (case-insensitive substring match).

mustAll

When true, every condition group must pass. When false (default), any single passing group triggers victory.

Key Run Parameters

All assist parameters are sent inside the assist field of the run body alongside the standard baseUrl, project, and steps fields.
// Validated by assistV2Schema in apps/api/src/routes/run.ts

{
  v2: true,                           // Required — enables the v2 pipeline
  goal: string,                       // Natural-language goal (required)
  isFullPlan?: boolean,               // Skip early-victory cutoff; replay full input plan
  maxHorizons?: number,               // 1–50; default from server config
  stepsPerHorizon?: number,           // 1–10; steps planned per horizon
  maxLoopMs?: number,                 // 10_000–3_600_000 ms total budget
  modalLoaderMaxWaitMs?: number,      // 3_000–600_000 ms; wait for modal loaders to clear
  maxHealingAttemptsPerStep?: number, // 0–3; healing retries per failed step
  observerMaxNodes?: number,          // 50–1000; accessibility tree size cap
  memoryMode?: "off" | "runtime" | "adaptive",
  victory?: {
    textIncludes?: string[],
    selectorVisible?: string[],
    urlIncludes?: string[],
    mustAll?: boolean,
  },
}

Triggering an Assisted v2 Run

The following example shows how to kick off a v2 assisted run using the Ghostly REST API. The steps array provides the initial navigation seed; the AI expands the plan from there.
const response = await fetch("http://localhost:4000/v1/run", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${apiKey}`,
  },
  body: JSON.stringify({
    project: "my-app",
    contextId: process.env.GIT_SHA,
    baseUrl: "https://staging.example.com",
    headless: true,
    steps: [{ action: "goto", url: "/" }], // Seed: navigate to root
    assist: {
      v2: true,
      goal: "Log in with test@example.com / password123 and verify the dashboard loads",
      maxHorizons: 10,
      stepsPerHorizon: 3,
      maxLoopMs: 120_000,
      maxHealingAttemptsPerStep: 2,
      memoryMode: "adaptive",
      victory: {
        urlIncludes: ["/dashboard"],
        textIncludes: ["Welcome"],
        mustAll: false,
      },
    },
  }),
});

const { id } = await response.json();
// → { ok: true, id: "uuid", status: "running" }

// Stream live events via SSE:
// GET http://localhost:4000/v1/runs/:id/stream
Assisted mode requires a configured LLM provider. If no provider is available, the API returns 409 assist v2 deshabilitado. Run ghostly config or set the ASSIST_LLM_PROVIDER environment variable before using assisted mode.

What Happens Inside a Horizon

This diagram illustrates the internal flow within a single horizon iteration:
horizon_start

    ├─ [if pendingSteps empty] → Strategist plans next batch → plan_chunk

    ├─ loop over steps in batch:
    │     step_start
    │     ├─ applyStep() succeeds → step_success → Observer snapshot → victory_check
    │     └─ applyStep() fails   → step_failure
    │           ├─ [if healingAttempts > 0] → heal_start → heal_action → heal_success/failure
    │           └─ [if unrecovered]         → replan from error → step_failure (final) → runOk=false

horizon_end → victory_check
Set stepsPerHorizon: 3 and maxHorizons: 15 as a starting point for most login-and-navigate flows. Increase maxLoopMs for flows that involve heavy data loading or modal animations.

Build docs developers (and LLMs) love