docs
    site-kit: For coding agents
    v7.2.0.md

    Integrating a site with Sonor — agent guide

    You installed @sonordev/site-kit. This file tells a coding agent how to wire a Next.js site to Sonor correctly and prove it works — no web access needed. Editing site-kit itself? See CONTRIBUTING.md.

    For the full machine-readable contract (modules, env, blessed patterns, failure modes, exit codes) run:

    npx sonor-setup manifest --json

    Everything below is also in that manifest. This file is the human-skimmable version.

    North star

    Take a bare Next.js repo → a fully wired, verified-green Sonor site. The signal that you are done is verify exiting 0 — not "the command ran."

    Canonical sequence

    npx sonor-setup manifest --json                              # discover the package
    npx sonor-setup init --api-key "$SONOR_API_KEY" --yes --json # wire layout + .env.local + postbuild
    npx sonor-setup scaffold --yes --json                        # sitemap, robots, llms, proxy
    npx sonor-setup mcp --yes --json                             # agent tools: MCP endpoint, card, relay (optional)
    # Existing 2.x-6.x site? migrate deterministically:
    npx sonor-setup codemod --check --json                       # exit 1 ⇒ work pending
    npx sonor-setup codemod --write --json                       # apply (idempotent, minimal diffs)
    next build                                                   # you run the build
    npx sonor-setup verify --json                                # exit 0 === done

    The machine contract

    • Every agent-native command supports --json and prints exactly ONE JSON envelope to stdout (all human logs go to stderr). Parse stdout; branch on exitCode / ok / checks.
    • Exit codes: 0 OK · 1 FAILED (result is red, fix the code) · 2 USAGE (bad invocation) · 3 CONFIG (missing input — the error names the flag) · 4 NETWORK (API/key) · 5 INTERNAL.
    • Never interactive under --json, --yes, or a non-TTY. A command that needs input exits 3 with an actionable fix instead of hanging.
    • Each checks[] finding has a stable id, a fix, and often a fixCommand you can run directly.

    The one env var

    The only variable a site needs is:

    SONOR_API_KEY=sonor_1a2b3c4d_...   # server-side only — NO NEXT_PUBLIC_ prefix

    SiteKitLayout reads it server-side and derives the project id + all client config. Never add NEXT_PUBLIC_SONOR_API_KEY, UPTRADE_API_KEY, NEXT_PUBLIC_UPTRADE_API_KEY, or SONOR_PROJECT_ID. Uptrade keys/vars are fully deprecated. Key format: sonor_{project-uuid-first8}_{secret}.

    Blessed patterns

    Root layout — SiteKitLayout (a server component), wrap {children}:

    import { SiteKitLayout } from '@sonordev/site-kit/layout'
    
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body>
            <SiteKitLayout>{children}</SiteKitLayout>
          </body>
        </html>
      )
    }

    Use SiteKitLayout, never the deprecated SiteKitProvider (it forces the whole tree client-side and breaks RSC/SSR). codemod migrates it for you.

    Analytics is already a deferred, childless sibling. Don't wrap {children}, and don't hand-roll it. Since 3.0.2, SiteKitLayout renders {children} first and mounts analytics, chat, popups and the fleet heartbeat after it, deferred to window load + idle (or the first interaction). 4.0.0 removed the last wrappers. So the plain layout above is the whole pattern: configure analytics with analytics={{ ... }}, and track custom events with the standalone trackEvent / trackConversion from @sonordev/site-kit/analytics (no provider needed; useAnalytics() throws outside one).

    What still de-opts a statically prerenderable route to 100% client rendering (the hero paints only after hydration; mobile LCP tanks) is a component you wrap around {children} that skips server rendering, usually next/dynamic({ ssr: false }). The old SiteKitLayout analytics={false} plus a hand-rolled deferred sibling was the workaround for site-kit <3.0.2. On those installs, upgrade.

    Agent tools — the built-in Sonor MCP server (7.0). Don't hand-write business-info, FAQ or review tools; npx sonor-setup mcp wires sonorMcpServer from @sonordev/site-kit/mcp/sonor, and a site's own tools go in its tools array. send_inquiry needs the person's go-ahead (person_confirmed: true) and a form with "Agent inquiries" on in Sonor. Pass onToolCall: reportToolCallsToSonor() to createMcpHandler so Sonor sees which agents called. A site that already runs its own MCP server is a custom implementation: sonor-setup mcp leaves it alone, and so should you; add reporting to it rather than replacing it.

    Imports: from a module's entry (@sonordev/site-kit/sync, /website/images, /seo/llms), never the root, which is types-only. The package is ESM only.

    Common failure modes → the check that catches it

    SymptomCauseFixdoctor/verify check
    Mobile LCP ~4s; server HTML is an empty shell + self.__next_f flight data, no <section>/<h1>Something wraps {children} in a component that skips SSR, usually next/dynamic({ ssr: false }) (e.g. the site's own lazy Providers) → 100% CSR. Never a plain SiteKitLayout on site-kit ≥3.0.2Keep the layout. Import that wrapper statically or mount it as a childless sibling. On <3.0.2, upgradessr.render
    Build throws "runtime is not available in proxy" / codemod skips middleware.tsNext 16's proxy.ts always runs on Node and rejects a runtime export; middleware.ts still accepts itRemove the runtime export, then npx sonor-setup codemod --write moves the file to proxy.tsmiddleware.netlify
    Invalid-key console spam; data features paused (401/403)Stale/rotated key, or an env change wasn't redeployedPut the current sonor_ key in .env.local and redeploykey.valid
    Deprecated SiteKitProvider in layout2.x integrationnpx sonor-setup codemod --only provider-to-layout --writelayout.sitekit
    @uptrademedia/site-kit / UPTRADE_* remnantspre-rebrand sitenpx sonor-setup codemod --only uptrade-to-sonor --writepackage.installed / env.api-key
    Hero present but LCP lateabove-the-fold element is opacity:0 + JS entrance-animatedRender hero fully static; gate reveal animations below the fold—

    Verifying (definition of done)

    npx sonor-setup verify --json              # static health + key validity + SSR (from .next build)
    npx sonor-setup verify --url https://your-site.com --json   # SSR check against a live/preview URL (strongest)

    verify exits 0 only when the integration is genuinely green. If it exits non-zero, read checks[] — each red check carries a fix (and often a fixCommand), and nextSteps[] names what to run. Loop until green.