ARCY AIv1.0
QuickstartPrompts

Cursor

Paste this prompt into Cursor to integrate the ARCY SDK end to end in one shot.

Open Cursor in your project and paste the entire prompt below into the chat. Cursor will detect your framework and auth library, wire up ARCYProvider with correct identity, add data-arcy attributes to key UI elements, and generate the .arcy/ knowledge graph. Run the install command in your terminal first.

Before you paste

Install the package in your terminal:

bash
npm install @arcyai/sdk
bash
pnpm add @arcyai/sdk
bash
bun add @arcyai/sdk
bash
yarn add @arcyai/sdk

Then add your keys to your env file:

Add to .env.local:

bash
NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY=pk_live_YOUR_KEY_HERE
ARCY_SECRET_KEY=sk_live_YOUR_KEY_HERE

Add to .env:

bash
VITE_ARCY_PUBLISHABLE_KEY=pk_live_YOUR_KEY_HERE
ARCY_SECRET_KEY=sk_live_YOUR_KEY_HERE

Setup prompt

arcy-setup-cursor-prompt.md
# Integrate the ARCY SDK into this codebase

ARCY (@arcyai/sdk) is already installed. Wire it up completely and generate the `.arcy/` knowledge graph. Follow every phase in order.

---

## Phase 1: Detect the project setup

Read `package.json` and the directory structure. Determine:

**Framework** (check in this order):
- `next` in dependencies AND `app/` or `src/app/` exists -> Next.js App Router
- `next` in dependencies AND `pages/` or `src/pages/` exists -> Next.js Pages Router
- `vite` AND `react` in dependencies -> Vite + React
- Otherwise -> ask the user before continuing

**Auth library** (check dependencies):
- `@clerk/nextjs` or `@clerk/react` -> Clerk
- `next-auth` -> NextAuth
- `@auth0/nextjs-auth0` or `@auth0/auth0-react` -> Auth0
- `@supabase/supabase-js` -> Supabase
- `firebase` -> Firebase
- None found -> proceed without identity (note this to the user)

Print a detection summary before making any file changes.

---

## Phase 2: Wrap the app in ARCYProvider

`ARCYProvider` is a React client component. It must wrap the entire app. Pass `publicKey` always. Pass `userId` and `userTraits` when auth is detected so sessions are tied to real users in the ARCY dashboard.

### CRITICAL RULES FOR WRAPPING

1. **Read the existing layout/app file first.** Identify every provider already wrapping `{children}` (e.g. ClerkProvider, ThemeProvider, SessionProvider, QueryClientProvider). ArcyWrapper must be placed INSIDE the existing provider tree, as the innermost wrapper around `{children}`. Never place it outside auth providers or it will lose access to auth context.

2. **Preserve all existing code.** Do not remove, reorder, or simplify existing imports, providers, metadata exports, className props on `<body>`, or any other code. Only add the ArcyWrapper import and the `<ArcyWrapper>` tags. Show a diff or clearly mark what was added vs what existed.

3. **Style import path:** The styles import is `@arcyai/sdk/styles`. If this import causes a build error, try `@arcyai/sdk/dist/styles.css` as a fallback, then `@arcyai/sdk/styles.css`. Log which one worked.

4. **`"use client"` enforcement:** The ArcyWrapper component file must have `"use client"` at the top. The layout file (`app/layout.tsx`) must NOT be converted to a client component. If auth data is needed server-side (Clerk, NextAuth, Supabase), fetch it in the layout as a Server Component and pass it as props to the client ArcyWrapper. For Firebase (client-only auth), the wrapper handles auth internally and the layout stays a Server Component.

Choose the correct implementation based on what you detected:

### Next.js App Router + Clerk

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

interface ArcyWrapperProps {
  userId?: string | null
  userEmail?: string | null
  children: React.ReactNode
}

export function ArcyWrapper({ userId, userEmail, children }: ArcyWrapperProps) {
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={userId ?? undefined}
      userTraits={userEmail ? { email: userEmail } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

In the root `app/layout.tsx`, add server-side auth fetching and wrap `{children}` with ArcyWrapper INSIDE the existing provider tree:

```tsx
// ADD these imports (keep all existing imports)
import { auth, currentUser } from "@clerk/nextjs/server"
import { ArcyWrapper } from "@/components/arcy-wrapper"

// In the RootLayout function body, ADD these lines before the return:
const { userId } = await auth()
const user = userId ? await currentUser() : null

// In the JSX, wrap {children} with ArcyWrapper INSIDE existing providers:
// BEFORE:
//   <ClerkProvider>
//     <ThemeProvider>
//       {children}
//     </ThemeProvider>
//   </ClerkProvider>
//
// AFTER:
//   <ClerkProvider>
//     <ThemeProvider>
//       <ArcyWrapper userId={userId} userEmail={user?.primaryEmailAddress?.emailAddress ?? null}>
//         {children}
//       </ArcyWrapper>
//     </ThemeProvider>
//   </ClerkProvider>
```

### Next.js App Router + NextAuth

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

interface ArcyWrapperProps {
  userId?: string | null
  userEmail?: string | null
  children: React.ReactNode
}

export function ArcyWrapper({ userId, userEmail, children }: ArcyWrapperProps) {
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={userId ?? undefined}
      userTraits={userEmail ? { email: userEmail } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

In `app/layout.tsx`, add:

```tsx
// ADD these imports (keep all existing imports)
import { getServerSession } from "next-auth"
import { authOptions } from "@/lib/auth"  // adjust path to where your authOptions live
import { ArcyWrapper } from "@/components/arcy-wrapper"

// In the RootLayout function body, ADD:
const session = await getServerSession(authOptions)

// Wrap {children} INSIDE existing providers:
<ArcyWrapper
  userId={session?.user?.id ?? null}
  userEmail={session?.user?.email ?? null}
>
  {children}
</ArcyWrapper>
```

### Next.js App Router + Supabase

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

interface ArcyWrapperProps {
  userId?: string | null
  userEmail?: string | null
  children: React.ReactNode
}

export function ArcyWrapper({ userId, userEmail, children }: ArcyWrapperProps) {
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={userId ?? undefined}
      userTraits={userEmail ? { email: userEmail } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

In `app/layout.tsx`, add:

```tsx
// ADD these imports (keep all existing imports)
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { cookies } from "next/headers"
import { ArcyWrapper } from "@/components/arcy-wrapper"

// In the RootLayout function body, ADD:
const supabase = createServerComponentClient({ cookies })
const { data: { user } } = await supabase.auth.getUser()

// Wrap {children} INSIDE existing providers:
<ArcyWrapper
  userId={user?.id ?? null}
  userEmail={user?.email ?? null}
>
  {children}
</ArcyWrapper>
```

### Next.js App Router + Firebase

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { useEffect, useState } from "react"
import { onAuthStateChanged, type User } from "firebase/auth"
import { auth } from "@/lib/firebase"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

export function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null)

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, setUser)
    return unsubscribe
  }, [])

  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={user?.uid ?? undefined}
      userTraits={user?.email ? { email: user.email } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

**Note:** This version uses Firebase's native `onAuthStateChanged`. If the project already has `react-firebase-hooks` installed, you may use `useAuthState(auth)` instead. The layout file stays as a Server Component since Firebase auth is client-only.

In `app/layout.tsx`, add:

```tsx
// ADD this import (keep all existing imports)
import { ArcyWrapper } from "@/components/arcy-wrapper"

// Wrap {children} INSIDE existing providers:
<ArcyWrapper>{children}</ArcyWrapper>
```

### Next.js App Router + Auth0

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { useUser } from "@auth0/nextjs-auth0/client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

export function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const { user } = useUser()
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={user?.sub ?? undefined}
      userTraits={user?.email ? { email: user.email } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

In `app/layout.tsx`, add:

```tsx
// ADD this import (keep all existing imports)
import { ArcyWrapper } from "@/components/arcy-wrapper"

// Wrap {children} INSIDE existing providers (must be inside UserProvider):
<ArcyWrapper>{children}</ArcyWrapper>
```

### Next.js App Router (no auth detected)

Create `components/arcy-wrapper.tsx`:

```tsx
"use client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

export function ArcyWrapper({ children }: { children: React.ReactNode }) {
  return (
    <ARCYProvider publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}>
      {children}
    </ARCYProvider>
  )
}
```

In `app/layout.tsx`, add:

```tsx
// ADD this import (keep all existing imports)
import { ArcyWrapper } from "@/components/arcy-wrapper"

// Wrap {children} INSIDE existing providers:
<ArcyWrapper>{children}</ArcyWrapper>
```

Once auth is added to this project, pass `userId` and `userTraits` from the auth session through `ArcyWrapper` into `ARCYProvider`.

### Next.js Pages Router + Clerk

Update `pages/_app.tsx`:

```tsx
import { useAuth } from "@clerk/nextjs"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"
import type { AppProps } from "next/app"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const { userId } = useAuth()
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={userId ?? undefined}
    >
      {children}
    </ARCYProvider>
  )
}

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ArcyWrapper>
      <Component {...pageProps} />
    </ArcyWrapper>
  )
}
```

### Next.js Pages Router + NextAuth

Update `pages/_app.tsx`:

```tsx
import { useSession } from "next-auth/react"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"
import type { AppProps } from "next/app"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const { data: session } = useSession()
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={session?.user?.id ?? undefined}
      userTraits={session?.user?.email ? { email: session.user.email } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ArcyWrapper>
      <Component {...pageProps} />
    </ArcyWrapper>
  )
}
```

### Next.js Pages Router + Supabase

Update `pages/_app.tsx`:

```tsx
import { useUser } from "@supabase/auth-helpers-react"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"
import type { AppProps } from "next/app"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const user = useUser()
  return (
    <ARCYProvider
      publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!}
      userId={user?.id ?? undefined}
      userTraits={user?.email ? { email: user.email } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ArcyWrapper>
      <Component {...pageProps} />
    </ArcyWrapper>
  )
}
```

### Vite + React + Clerk

Add to `src/App.tsx`:

```tsx
import { useUser } from "@clerk/clerk-react"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const { user, isLoaded } = useUser()
  if (!isLoaded) return <>{children}</>
  return (
    <ARCYProvider
      publicKey={import.meta.env.VITE_ARCY_PUBLISHABLE_KEY}
      userId={user?.id ?? undefined}
      userTraits={
        user?.primaryEmailAddress
          ? { email: user.primaryEmailAddress.emailAddress }
          : undefined
      }
    >
      {children}
    </ARCYProvider>
  )
}
```

Wrap your existing root component with `<ArcyWrapper>`.

### Vite + React + Supabase

Add to `src/App.tsx`:

```tsx
import { useUser } from "@supabase/auth-helpers-react"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  const user = useUser()
  return (
    <ARCYProvider
      publicKey={import.meta.env.VITE_ARCY_PUBLISHABLE_KEY}
      userId={user?.id ?? undefined}
      userTraits={user?.email ? { email: user.email } : undefined}
    >
      {children}
    </ARCYProvider>
  )
}
```

Wrap your existing root component with `<ArcyWrapper>`.

### Vite + React (no auth)

Add to `src/App.tsx`:

```tsx
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"

function ArcyWrapper({ children }: { children: React.ReactNode }) {
  return (
    <ARCYProvider publicKey={import.meta.env.VITE_ARCY_PUBLISHABLE_KEY}>
      {children}
    </ARCYProvider>
  )
}
```

Wrap your existing root component with `<ArcyWrapper>`.

---

## Phase 3: Add data-arcy attributes

Read EVERY page, layout, and component in the codebase. Add `data-arcy` attributes to ALL interactive and semantically important elements. These IDs let the AI assistant highlight elements, scroll to them, and reference them accurately when guiding users. More anchors = better AI accuracy. Fewer anchors = blind spots where the AI cannot point users to the right place.

### Rules

**Naming:**
- Use lowercase hyphen-separated IDs that describe what the element does: `create-project-button`, not `top-right-button`
- For repeated/mapped elements (e.g. sidebar nav items, list rows), include the distinguishing identifier: `nav-dashboard`, `nav-settings`, `nav-billing`, not just `nav-item`
- Each `data-arcy` value must be GLOBALLY UNIQUE across the entire codebase. No two elements may share the same ID.

**What to annotate (annotate ALL of these, not a subset):**
- Every navigation link and menu item (sidebar, topbar, tabs, breadcrumbs)
- Every primary and secondary action button (create, save, delete, cancel, submit, export, import, invite, upgrade, downgrade)
- Every form and its submit button (login form, settings form, create entity form)
- Every input field that the user interacts with (search, filters, text inputs, selects, date pickers, toggles)
- Every section/container that represents a distinct functional area (billing section, team members list, activity feed, stats cards, onboarding checklist)
- Every empty state and its CTA
- Every modal/dialog trigger button
- Every dropdown menu trigger
- Every table header and key table actions
- Every card or list item that represents a core entity (project card, user row, invoice row)
- Every status indicator or badge that the AI might need to reference

**What NOT to annotate:**
- Pure decorative elements (icons with no interaction, dividers, spacers)
- Elements that are NEVER visible (hidden debug panels, feature-flagged elements not in production)

**Conditional/dynamic elements:**
- For elements inside modals, drawers, popovers, or conditionally rendered blocks: add `data-arcy` to BOTH the trigger button AND the elements inside the modal/drawer. Document which anchors are conditional in the route YAML `elements` array (Phase 4).
- For elements rendered via `.map()` over dynamic data: add `data-arcy` with a template pattern using the item's stable identifier. Example:
  ```tsx
  {projects.map(p => (
    <div key={p.id} data-arcy={`project-card-${p.slug}`}>...</div>
  ))}
  ```
  In the route YAML, document the pattern as `anchorId: project-card-{slug}` and note it is dynamic.

**There is no upper limit on the number of anchors.** A small app might have 20-30. A medium app should have 50-100+. A large app could have 200+. Cover everything.

```tsx
<button data-arcy="create-project-button">Create project</button>
<nav data-arcy="main-sidebar">
  <a href="/dashboard" data-arcy="nav-dashboard">Dashboard</a>
  <a href="/settings" data-arcy="nav-settings">Settings</a>
  <a href="/billing" data-arcy="nav-billing">Billing</a>
</nav>
<button data-arcy="upgrade-plan-button">Upgrade plan</button>
<input data-arcy="global-search-input" type="search" />
<button data-arcy="open-create-modal">New item</button>
<dialog data-arcy="create-item-modal">
  <input data-arcy="create-item-name-input" />
  <button data-arcy="create-item-submit">Create</button>
</dialog>
```

Keep a complete list of every `data-arcy` ID you add, noting which are conditional (inside modals/drawers) and which are dynamic (template patterns). You need this list in Phase 4.

---

## Phase 4: Generate the `.arcy/` knowledge graph

Create the `.arcy/` directory at the project root. This is the ARCY backend's knowledge base: what the product is, what each page does, the domain entities, and guided walkthroughs. The backend reads these YAML files at query time to give accurate, product-specific answers.

Fill in the content by reading the codebase. Do not use generic placeholders for the app name or feature descriptions.

### Create `.arcy/app.yaml` (required)

This file is always injected into every AI response. Every field you omit is context the AI will not have.

```yaml
app:
  name: "[actual app name from codebase]" # required
  description: "[what this SaaS does and who uses it — 1-2 sentences from the codebase]" # required

navigation: # optional but strongly recommended — add every route you found
  - path: /dashboard
    label: Dashboard
    description: "[what this page does]"
  # continue for every route in the codebase

terminology: # optional — product-specific vocabulary
  - term: "[domain-specific term]"
    definition: "[what it means in this specific product]"

personas: # optional — user types
  - id: admin
    name: Admin
    description: "[what admin users do in this product]"
```

### Create `.arcy/routes/[slug].yaml` for each distinct route

The slug is the first path segment: `/settings/team``settings.yaml`. File names must be `[a-z0-9-]+.yaml`. For the route `/settings/team`, the file is `routes/settings.yaml`.

```yaml
route:
  path: /dashboard # required
  label: Dashboard # required
  description: "[what this page does]"
  purpose: "[what a user comes here to accomplish]"

sections: # optional — distinct functional areas on this page
  - id: overview
    label: "[section name]"
    anchorId: "[data-arcy ID of this section from Phase 3]"
    description: "[what this section shows or does]"
    elements:
      - anchorId: "[data-arcy ID of an interactive element in this section]"
        label: "[element label]"
        type: button
        description: "[what this element does]"

help: # optional
  summary: "[one sentence describing the page]"
  faq:
    - question: "[common user question about this page]"
      answer: "[answer]"
      relatedElements: ["[data-arcy ID]"]
```

### Create `.arcy/entities/[id].yaml` for core domain entities (optional)

Only create these for the main domain objects in the product. Skip if the app has no complex entities.

```yaml
entity:
  id: project # required
  name: Project # required
  description: "[what this entity is in the product]"

fields: # optional
  - id: status
    label: Status
    type: enum
    description: "[what this field controls]"
    enumValues:
      - value: active
        label: Active
        description: "[what active means in this product]"
```

### Create `.arcy/flows/[id].yaml` for guided walkthroughs

Create at least 2 flows:
1. **`onboarding`** — walks a new user through the first-time experience
2. A **feature discovery** flow for a core feature users commonly miss

Steps with `anchorId` are executable by Teach mode (the AI highlights those elements in sequence). Steps without `anchorId` are AI context only. Both are valid.

```yaml
flow:
  id: onboarding # required — lowercase, matches the file name
  name: Get Started # required
  description: "[what this flow helps the user accomplish]"
  goal: "[what the user wants to achieve — e.g. 'Create your first project and invite your team']"
  persona: admin # optional — target user type

steps:
  - order: 1
    title: "[step title]"
    description: "[what the user sees or does here]"
    route: /dashboard # optional — the page this step is on
    action: "[text description of what to do on this step]"
    anchorId: main-sidebar # optional — enables Teach mode, must match a data-arcy ID from Phase 3
  - order: 2
    title: "[next step title]"
    description: "[what the user does next]"
    route: /dashboard
    action: "Click here to [primary action description]"
    anchorId: create-project-button
```

CRITICAL rules for flow `anchorId` values:
- Every `anchorId` must match a `data-arcy` ID you added in Phase 3
- Only use `anchorId` for elements always in the DOM on that route
- Never reference elements inside modals or drawers unless a previous step opens that modal/drawer first

After creating all files, the structure should look like:

```
.arcy/
  app.yaml
  routes/
    dashboard.yaml
    settings.yaml
    [other route slugs].yaml
  entities/
    [entity-id].yaml    (if applicable)
  flows/
    onboarding.yaml
    [feature-discovery-id].yaml
```

---

## Phase 5: Verify

Confirm all of the following before finishing:

1. `ARCYProvider` wraps the entire app, INSIDE any existing provider tree (not outside auth/theme providers)
2. `@arcyai/sdk/styles` is imported in the provider file (confirm import does not cause build errors)
3. The publishable key env var is in `.env.local` or `.env`
4. `.arcy/app.yaml` exists with `app.name` and `app.description` filled in (no placeholder values remaining)
5. Route YAML files exist in `.arcy/routes/` for each distinct route in the app
6. At least 2 flow YAML files exist in `.arcy/flows/`
7. `data-arcy` attributes comprehensively cover the app (every nav item, every action button, every form field, every section container, every entity card/row)
8. Every `data-arcy` value is globally unique across the codebase (run a grep to verify: `grep -roh 'data-arcy="[^"]*"' src/ app/ components/ pages/ | sort | uniq -d` should return empty)
9. Flow step `anchorId` values reference `data-arcy` IDs you added in Phase 3
10. No flow step `anchorId` references an element inside a modal/drawer unless a previous step opens it
11. The `app/layout.tsx` file is still a Server Component (no `"use client"` added to it)

Print a summary of:
- Every file changed (with what was changed)
- Total number of `data-arcy` attributes added
- Every `.arcy/` YAML file created (key content: app name, route count, flow names and step counts)
- Any warnings (e.g. conditional anchors referenced in flows, auth library not found)

After Cursor finishes

  1. Push your configuration:
bash
arcy push
arcy status
  1. Start your dev server. A floating widget should appear in the bottom-center.

What's next

On this page