Ghostly is a local-first runtime composed of several cooperating packages, all orchestrated by a single CLI. Understanding how they fit together helps you configure the engine correctly, extend it for your workflow, and debug unexpected behaviour. This page walks through the monorepo layout, each component’s responsibilities, and the request lifecycle for an assisted run.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.
Local-first by design. All cryptographic keys, LLM credentials, run artifacts, and test data are stored on the developer’s machine — in
~/.ghostly/auth.json and a local SQLite database. Ghostly makes no outbound connections to a Ghostly cloud service. The only external network calls are the ones you configure: to your chosen LLM provider endpoint.Monorepo layout
@ghostly-io npm scope. The CLI bundles the compiled API, web dashboard, and MCP server as embedded assets so a single npm install -g @ghostly-io/cli is all end-users need.
Components in detail
CLI — @ghostly-io/cli
CLI — @ghostly-io/cli
The CLI is the single entry point for developers. It is published to npm as
Auth file structure (
@ghostly-io/cli and registered as the ghostly binary (with the legacy alias ghost kept for backwards compatibility).What it does- Zero-config installer —
ghostly installsaves credentials to~/.ghostly/auth.json, writes the MCP server configuration to~/.cursor/mcp.json, installs Chromium via Playwright, and copies Cursor rules and skills to~/.cursor/. - Credential management —
ghostly keygengenerates a UUID (or hex token) API key and persists it to~/.ghostly/auth.json. Every subsequent CLI command reads from this file. - Engine launcher —
ghostly uprunsprisma db pushto migrate the local SQLite schema, generates the Prisma client, seeds the initial admin user on a fresh database, and then spawns the bundled API server process with all required environment variables injected.
| Command | Description |
|---|---|
ghostly keygen | Generates a UUID API key and saves it to ~/.ghostly/auth.json. Pass --token for a random hex token instead. |
ghostly install | Saves credentials, configures the MCP server in ~/.cursor/mcp.json, installs Chromium, and syncs Cursor rules/skills. |
ghostly config | Interactive prompt to set the LLM provider, model, API key, and base URL. Pass --clear to reset. |
ghostly up [-p PORT] | Migrates the SQLite DB, generates the Prisma client, and starts the API + dashboard (default: port 4000). |
ghostly update | Updates the globally installed CLI to the latest published version. |
~/.ghostly/auth.json)API — apps/api
API — apps/api
The API is a Hono HTTP server bundled inside the CLI’s npm package. It is launched by
AuthenticationThe API supports two parallel auth mechanisms:
ghostly up and listens on 127.0.0.1:4000 by default.PersistenceGhostly uses Prisma with a SQLite backend. The database file is created automatically on first run. Key models:| Model | Purpose |
|---|---|
User | Dashboard accounts with email + hashed password. Role: admin or member. |
ApiKey | Per-user API keys for programmatic access. |
Project | Groups runs by label and colour. |
Run | A single test execution: status, base URL, assisted metadata, and code hints. |
Step | Individual Playwright actions within a run, with screenshot paths and a11y snapshots. |
RunEvent | Ordered SSE event log for each run — streamed live to the dashboard. |
AssistMemory | Cached successful step plans per (userId, project, baseUrl, goal) — replayed on future runs. |
UserLlmSettings | Per-user LLM provider, model, API key, and base URL overrides. |
- JWT (
Authorization: Bearer <token>) — issued byPOST /v1/auth/loginfor dashboard users. - API key (
X-Api-Key: <key>) — the key from~/.ghostly/auth.json, used by the CLI and MCP server.
Runner — @ghostly-io/runner
Runner — @ghostly-io/runner
The runner is the Playwright execution engine. It exposes two public functions:
ArtifactsOn failure (or when explicitly enabled), the runner saves:
runFlow(input: RunInput, opts?): Promise<RunResult>Executes a pre-defined list of steps directly — no LLM involvement. Each step is one of:| Action | Description |
|---|---|
goto | Navigate to a URL (same-origin enforced by default). |
click | Click an element using smart selector fallbacks. |
fill | Type into an input or textarea, with field-type expansion. |
press | Send a keyboard key press. |
waitForSelector | Wait until an element is visible. |
snapshot | Capture an accessibility tree snapshot. |
runAssistedFlow (the AI-driven mode)Invoked when a goal string is supplied instead of a step list. The pipeline works in horizons:- Strategist — the LLM receives the goal, the current page URL, and optional
codeHintsfrom the Scanner. It returns the next batch of steps (a horizon). - Observer — after each step, Playwright captures the live accessibility tree (
page.locator("body").ariaSnapshot({ mode: "ai" })). The snapshot is fed back to the strategist for the next horizon. - Healer — if a selector throws, the healer agent reads the a11y snapshot and proposes a repaired selector. The step is retried before being marked as failed.
click or fill, the runner expands the primary selector into a list of fallback candidates (e.g. a button:has-text("Login") selector also tries getByRole("button", { name: /Login/i })). The first candidate that resolves within the timeout wins; all errors are collected and surfaced as a single descriptive message if every candidate fails.Guardrails (from schema.ts)- Screenshots — per-step PNG files (
step-N-ok.png/step-N-failed.png). - Video — a
.webmrecording of the full run. - Console logs — up to 40 browser console messages captured during the run.
- Detected alerts — visible toast/dialog messages collected from well-known CSS selectors.
Dashboard — apps/web
Dashboard — apps/web
The dashboard is a React SPA built with Vite. In production it is served as static files by the API server itself — the
Real-time updates via SSEThe dashboard subscribes to
GHOST_WEB_DIR environment variable points apps/api to the compiled dist/ folder bundled inside the CLI package.Key views| View | Description |
|---|---|
| Overview | Summary cards: total runs, pass rate, recent activity. |
| Runs panel | Filterable list of all runs with status badges and duration. |
| Run detail | Step-by-step timeline with screenshots, a11y snapshots, and detected alerts. Video replay when a recording is available. |
| LLM settings | Per-user form to override the provider, model, API key, and base URL saved in user_llm_settings. |
GET /v1/runs/:id/events/stream as a Server-Sent Events stream. Each RunEvent row written by the API during execution is pushed to the client in sequence, updating the step timeline without polling.MCP Server — packages/mcp-server
MCP Server — packages/mcp-server
The MCP server bridges MCP-compatible IDEs (primarily Cursor) to Ghostly’s local REST API. It is injected into
~/.cursor/mcp.json by ghostly install and communicates with the API using the key from ~/.ghostly/auth.json.Exposed tools| Tool | Description |
|---|---|
ghostly_run_flow | Submit a goal (or a step list) for a given project and base URL. Returns a run ID and status. |
submit_plan | Push a manually authored step plan to the API for immediate execution. |
get_project_map | Return the Scanner’s route/component map for a target repository — useful for giving the LLM context. |
analyze_component | Run the Scanner on a specific component file and return its extracted selectors and props. |
list_ghostly_projects | List all projects belonging to the current user. |
read_flow_docs | Retrieve built-in Ghostly flow documentation for IDE-side prompt augmentation. |
Scanner — packages/scanner
Scanner — packages/scanner
The Scanner performs static AST analysis of a target repository to extract routes, React/Vue components, and CSS selectors. The output (
codeHints) is attached to the Run record and injected into the LLM strategist prompt as grounding context — helping the AI make more accurate selector predictions even before the browser opens.The Scanner is invoked by the MCP get_project_map tool and can also be called directly from the API via the plan route when codeHints are not yet available.Client SDK — @ghostly-io/client
Client SDK — @ghostly-io/client
@ghostly-io/client is a lightweight TypeScript wrapper around the Ghostly REST API. It is intended for use in custom scripts, CI pipelines, or third-party integrations that need to submit goals, poll run status, or retrieve step results programmatically — without going through the CLI or MCP server.Assisted run lifecycle
The following sequence describes what happens from the moment a user submits a plain-English goal to the moment the dashboard shows a final verdict.User submits a goal
The user enters a goal and a target URL in the dashboard (or via the
ghostly_run_flow MCP tool in Cursor). The dashboard posts to POST /v1/run with the goal, project ID, and base URL. The API creates a Run record in SQLite with status running.API calls the LLM strategist
The API resolves the user’s LLM configuration (from
user_llm_settings or the environment), then calls the strategist with the goal, any codeHints from the Scanner, and the current run context. The strategist returns the first horizon of Playwright steps as structured JSON.Runner executes Playwright
The runner receives the step list and opens a headless Chromium browser. For each step it calls the appropriate Playwright action (
page.goto, page.click, page.fill, etc.) with smart selector fallback expansion. After every action it captures the a11y tree and any visible alerts.Observer feeds the next horizon
The a11y snapshot from step 3 is sent back to the strategist along with the outcomes so far. The strategist plans the next horizon. This loop continues until the goal’s victory conditions are met or the maximum horizon count is reached.
Healer repairs failures
If a selector throws, the healer agent receives the a11y snapshot and the failing step. It proposes a repaired selector and the runner retries before recording the step as failed. Successfully healed selectors are logged for diagnostics.
SSE events stream to the dashboard
Throughout execution the API writes
RunEvent rows for every step start, step success, step failure, and run completion. The dashboard’s SSE subscription on GET /v1/runs/:id/events/stream receives these events in real time and updates the step timeline live.Explore further
Assisted Mode
Deep-dive into the strategist–observer–healer pipeline and how horizons are planned.
Self-Healing Selectors
How the healer agent uses accessibility snapshots to repair broken selectors at runtime.
CLI Reference
Full flag reference for every
ghostly command, including advanced up options.API Reference
OpenAPI-style reference for all
/v1/* routes, request bodies, and response shapes.