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.

Every piece of work in Ghostly is organized around two core concepts: Projects and Runs. A Project is a named container that groups related runs together — think of it as a test suite, a micro-service, or a feature area. A Run is a single execution of a browser flow against a specific URL, containing every step taken, every screenshot captured, and the final pass/fail verdict. Understanding how these two entities relate is the foundation for navigating Ghostly’s dashboard, querying the API, and structuring your CI pipelines.

Projects

A Project is the top-level container for organizing test runs. Each project belongs to a single user and is identified by its id slug when submitting runs.
FieldTypeDescription
idstring (UUID)Unique identifier / slug used in run submissions
labelstringHuman-readable display name
colorstringHex color for dashboard display (e.g. #6366f1)
createdAtDateTimeISO timestamp of project creation
Projects appear in the dashboard sidebar and let you filter runs by product area or team.
A run’s project field must reference an existing project slug that belongs to the authenticated user. Submitting a run with an unknown project slug returns a 400 validation error.

Runs

A Run represents one complete execution of a browser flow — from navigating to baseUrl through every step, to the final pass or fail verdict.
// From packages/runner/src/schema.ts and run.ts

export type RunStatus = "pass" | "fail" | "running";

export type RunRecord = {
  id: string;             // UUID assigned at creation
  status: RunStatus;      // "running" → "pass" | "fail"
  startedAt: string;      // ISO 8601 timestamp
  durationMs: number;     // Total wall-clock time in ms
  baseUrl: string;        // Root URL the flow executed against
  project?: string;       // Project slug (required at API level)
  contextId?: string;     // Optional tag — e.g. a git commit SHA
  assisted?: AssistedMeta;// Present when run was AI-driven
  steps: StepOutcome[];   // Ordered results for each step
  videoPath?: string;     // Local path to failure video, if captured
};

export type StepOutcome = {
  index: number;          // Zero-based position in the run
  action: Step["action"]; // "goto" | "click" | "fill" | "press" | "waitForSelector" | "snapshot"
  ok: boolean;            // true = step succeeded
  error?: string;         // Error message if ok = false
  screenshotPath?: string;// Path to PNG screenshot artifact
  a11y?: unknown;         // Accessibility tree snapshot (if captured)
};

Step Types

Ghostly supports six primitive step actions, derived from stepSchema in packages/runner/src/schema.ts:

goto

Navigate to a URL relative to baseUrl, waiting for domcontentloaded.

click

Click a DOM element by CSS selector, with smart fallback expansion.

fill

Type a value into an input or textarea by selector.

press

Simulate a keyboard key press (e.g. Enter, Tab).

waitForSelector

Pause until an element is visible; optional timeoutMs override.

snapshot

Capture the page’s accessibility tree without performing any action.

Run Status Lifecycle

A run always starts in "running" and transitions to exactly one terminal state:
running  ──→  pass   (all steps succeeded, victory conditions met)
         ──→  fail   (a step failed, timeout exceeded, or victory not achieved)
The status field is updated atomically when the run finishes. The durationMs field reflects the total wall-clock time of the browser session.

The contextId Field

Use contextId to correlate runs with your CI system. Passing a git commit SHA makes it easy to group all runs triggered by the same pull request:
{
  "project": "my-app",
  "contextId": "a3f9c12",
  "baseUrl": "https://staging.example.com",
  "steps": [...]
}

Assisted Runs

When a run is driven by AI (assisted mode), the assisted field on RunRecord is populated with metadata about the LLM invocation, and the full event stream is available as events: AssistEvent[].
// From packages/runner/src/schema.ts

export type AssistedMeta = {
  goal: string;        // The natural-language goal provided
  model: string;       // LLM model used (e.g. "gpt-4o")
  generatedAt: string; // ISO timestamp of plan generation
  promptVersion: string;
  assistConfig?: {
    victory?: {
      textIncludes?: string[];
      selectorVisible?: string[];
      urlIncludes?: string[];
      mustAll?: boolean;
    };
    isFullPlan?: boolean;         // Full-plan mode (e.g. advanced MCP)
    maxHorizons?: number;
    stepsPerHorizon?: number;
    maxLoopMs?: number;
    modalLoaderMaxWaitMs?: number; // Max wait for modal loaders to clear
    memoryMode?: "off" | "runtime" | "adaptive";
  };
};

Assist Event Stream

For assisted runs, the full internal event log is stored as an ordered sequence of AssistEvent objects. These power the live dashboard view and are available via GET /v1/runs/:id.
Event typeWhen it fires
reconInitial page snapshot before any planning
plan_chunkStrategist produced a new batch of steps
loop_stateHorizon loop changed state (planning, executing, stopped)
horizon_startA new planning horizon began
horizon_endA planning horizon completed
victory_checkVictory conditions were evaluated
memory_hitSeed steps were loaded from assist memory
memory_missNo memory found for this goal/project/URL
step_startA step is about to execute
step_successA step completed successfully
step_failureA step threw an error
heal_startSelf-healing initiated for a failed step
heal_actionHealer proposed and applied a replacement step
heal_successSelf-healing recovered the failed step
heal_failureSelf-healing could not recover
run_endRun finished; includes final plan and progress summary

Run Artifacts

Ghostly captures several types of artifacts during a run, depending on configuration:
When captureScreenshotAfterEachStep: true, a PNG screenshot is saved after each step. The path is stored in StepOutcome.screenshotPath. On failure, a screenshot is always attempted regardless of the per-step setting.
When recordVideoOnFailure: true, Playwright records the browser session. The video is only kept if the run fails — successful runs have their video deleted to save disk space. The path is stored in RunRecord.videoPath.
When captureA11yAfterEachStep: true, or when a snapshot step is encountered, Ghostly captures the page’s accessibility tree using Playwright’s ariaSnapshot({ mode: "ai" }). The result is stored in StepOutcome.a11y and used by the AI pipeline for planning.
Set contextId to your CI commit SHA to make runs traceable in the Ghostly dashboard. You can filter runs by project and sort by startedAt to see per-commit test history.

Build docs developers (and LLMs) love