---
title: For Agentic App Builders
description: Make your existing SaaS or webapp something an AI agent can drive — without rewriting it. Vision page + waitlist for the agentic-app-builders track on ggui.
---

:::caution[Vision page]
This describes a direction, not a shipped product. If you're building agentic apps **today**, take the [Agent Builder track](/oss-quickstart/) — that path is live. The waitlist at the bottom is for early access to this track when its first adapter lands.
:::

## The shift

AI agents drive existing SaaS apps through three increasingly unreliable layers:

1. **Reading screenshots** — vision-language models reason about rendered pixels. Brittle, slow, no typed I/O.
2. **Browser automation** — Playwright / Puppeteer scripts wrapping flows. Snap the moment a button moves; the agent has no way to know the contract changed.
3. **Reading official APIs** — when they exist, and only for the slice the API covers. Most production apps keep a third of their behavior in the UI, not the API.

What's missing: a **typed contract** between the agent and an existing app's surface, so the agent can drive flows safely without parsing pixels or scraping markup.

That's the gap this track fills.

## What gguifying an app looks like

You add a small ggui adapter to your existing app. The adapter:

1. Exposes navigable routes as **renders** with typed contracts
2. Mirrors form fields as **`actionSpec`** (typed inbound actions that drive turns)
3. Mirrors visible state as **`contextSpec`** (read-only observable state the agent reacts to)
4. Wraps any browser-only library you use (Stripe Checkout, Mapbox, calendar pickers) as **gadgets** so the LLM knows how to compose with them

The agent then drives your app the same way it drives a freshly-generated ggui UI — via `ggui_handshake`, `ggui_render`, `ggui_consume`. Same MCP wire. Same contract guarantees.

**Critically:** the human-facing UI doesn't change. End-users keep clicking your buttons. Agents get a parallel typed surface onto the same flows.

## What you'd write

The provisional shape is a `ggui.app.json` next to your existing app config:

```json
{
  "name": "my-saas",
  "routes": [
    {
      "path": "/invoices/new",
      "intent": "create an invoice",
      "agentCapabilities": {
        "tools": {
          "createInvoice": {
            "toolInfo": { "inputSchema": { "$ref": "./schemas/invoice.json" } }
          }
        }
      },
      "actionSpec": {
        "submit": {
          "label": "Create invoice",
          "schema": { "$ref": "./schemas/invoice.json" },
          "nextStep": "createInvoice"
        }
      },
      "contextSpec": {
        "currentDraft": { "schema": { "$ref": "./schemas/invoice-draft.json" } }
      }
    }
  ]
}
```

Your app code stays as-is. An agent runtime can now discover `/invoices/new` from the adapter's catalog, `ggui_handshake` against its contract, and `ggui_render` with a typed payload — no clicking around. (Exact wire shape for app-catalog lookup is part of the SDK's in-design surface.)

## Three scenarios this unlocks

1. **Your support agent drives the app for the customer.** "Refund last month's invoice for customer X" → agent navigates to `/invoices/`, finds the row, calls `refund` with the typed payload. No human-in-the-loop browsing.

2. **Your sales engineer runs an agent-narrated demo.** During a prospect call, the agent narrates while driving the form in real-time. The prospect sees the same UI any user sees, but the agent's typed actions land like a polished guided tour.

3. **Power users hand work off to their AI.** "I have 40 of these to fill in — can my AI do it?" The AI has a typed surface to drive, not pixels to scrape.

## What's shipping when

| Component                                                 | Status    |
| --------------------------------------------------------- | --------- |
| ggui protocol (this site)                                 | Live      |
| Agent Builder track (build a ggui-native agent)           | Live      |
| Agentic App SDK (wrap an existing app)                    | In design |
| Hosted gguifier service on [guuey.com](https://guuey.com) | In design |
| Reference adapters for Next.js / Rails / Django           | Planned   |
| Reference adapters for legacy stacks (Java EE, Drupal, …) | Planned   |

No dates. Real engineering work, not a marketing roadmap.

## Waitlist

If this is the track you actually need, drop your email. We'll write when the first adapter ships and we have an early-access slot to fill.

<form
  class="waitlist-form"
  action="mailto:agentic@ggui.ai"
  method="post"
  enctype="text/plain"
>
  <label for="waitlist-email" class="waitlist-form__label">Email</label>
  <div class="waitlist-form__row">
    <input
      id="waitlist-email"
      type="email"
      name="email"
      required
      placeholder="you@company.com"
      autocomplete="email"
      class="waitlist-form__input"
    />
    <button type="submit" class="waitlist-form__submit">
      Join waitlist
    </button>
  </div>
  <p class="waitlist-form__note">
    Opens your mail client with a pre-filled message. We'll wire up a real
    intake form before the first adapter lands — until then this stays a
    direct mailto so nothing intermediates the signal.
  </p>
</form>

<style>
  .waitlist-form {
    margin: 1.5rem 0 0;
    padding: 1.5rem;
    border: 1px solid var(--ggui-line-2);
    background: var(--ggui-paper-2);
  }
  :root[data-theme="dark"] .waitlist-form {
    border-color: var(--ggui-line-2-dark);
    background: var(--ggui-paper-2-dark);
  }
  .waitlist-form__label {
    display: block;
    font-family: var(--sl-font-mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ggui-ink-3);
    margin-bottom: 0.5rem;
  }
  :root[data-theme="dark"] .waitlist-form__label {
    color: var(--ggui-ink-3-dark);
  }
  .waitlist-form__row {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
  }
  .waitlist-form__input {
    flex: 1 1 16rem;
    min-width: 0;
    padding: 0.625rem 0.875rem;
    background: var(--ggui-paper);
    border: 1px solid var(--ggui-line-2);
    border-radius: 0;
    font-family: inherit;
    font-size: 14px;
    color: var(--ggui-ink);
  }
  :root[data-theme="dark"] .waitlist-form__input {
    background: var(--ggui-paper-dark);
    border-color: var(--ggui-line-2-dark);
    color: var(--ggui-ink-dark);
  }
  .waitlist-form__input:focus {
    outline: none;
    border-color: var(--ggui-ink);
  }
  :root[data-theme="dark"] .waitlist-form__input:focus {
    border-color: var(--ggui-ink-dark);
  }
  .waitlist-form__submit {
    padding: 0.625rem 1.25rem;
    background: var(--ggui-ink);
    color: var(--ggui-paper);
    border: 1px solid var(--ggui-ink);
    border-radius: 0;
    font-family: var(--sl-font-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
  }
  .waitlist-form__submit:hover {
    background: var(--ggui-ink-2);
    border-color: var(--ggui-ink-2);
  }
  :root[data-theme="dark"] .waitlist-form__submit {
    background: var(--ggui-ink-dark);
    color: var(--ggui-paper-dark);
    border-color: var(--ggui-ink-dark);
  }
  :root[data-theme="dark"] .waitlist-form__submit:hover {
    background: var(--ggui-ink-2-dark);
    border-color: var(--ggui-ink-2-dark);
  }
  .waitlist-form__note {
    margin: 0.75rem 0 0;
    font-size: 12px;
    line-height: 1.55;
    color: var(--ggui-ink-3);
  }
  :root[data-theme="dark"] .waitlist-form__note {
    color: var(--ggui-ink-3-dark);
  }
</style>

## Related

- [How ggui works](/how-it-works/) — the protocol's four moments. The gguify pattern reuses the same handshake → render → interact → consume loop, just driven by your app's routes instead of LLM-generated UI.
- [Glossary](/glossary/) — `actionSpec`, `contextSpec`, `gadget`, `tool`, `blueprint`.
- [For LLM agents](/agents/) — machine-readable resources, including this page at [`/agentic-app-builders.md`](/agentic-app-builders.md).