# Vibe coding with Claude Code or Cursor: one skill, then sign-in, teams and billing

> In a coding agent the SDK installs in your own repo, so the whole job is making the agent know it exists. One skill line, one init command, one prompt, and what to check in the diff it hands back.

- Source: https://www.buildbase.app/guides/vibe-coding-with-claude-code-or-cursor
- Section: Guides
- Author: Dharmendra Jagodana
- Published: 2026-10-27

## In short

To add sign-in, teams and billing to an app with Claude Code or Cursor, install the BuildBase skill first (npx skills add buildbase-app/claude-skill), run npx buildbase init with your organization id, then prompt for the outcome. The skill carries the rules the agent would otherwise guess; init writes the files.

In a coding agent, the hard part is not the code. The SDK is one
`npm install` away and the agent can type it. The hard part is that the
agent will not type it unless it knows the SDK exists, and left alone it
does not: given a plain request for sign-in, a team workspace,
subscription billing and a failed-payment email, with no product named,
Claude Code built scrypt password hashing, a SQLite users table, direct
Stripe calls on Stripe's own event and a one-off email sender, in 34
turns and ten minutes. Correct, and yours to maintain forever.

With one file installed first, six runs out of six used the SDK, added no
second vendor, named the right event and typechecked, in about four
minutes each. [The full write-up](/blog/what-a-coding-agent-builds-when-nobody-tells-it-otherwise)
has the record. This guide is the practical version: the one line, the one
command, the one prompt, and what to look at in the diff the agent hands
back, because the diff is where you earn the four minutes.

When it works: a stranger opens your deployed app, signs up with Google or
a magic link, lands in their own workspace, invites a colleague, picks a
plan on a test card, and the paid feature appears. Your `package.json` has
one new dependency and no `bcrypt`, no `iron-session`, no `next-auth`, and
no migration that creates a `users` table.

What we ran on 27 October 2026: the skill install and `npx buildbase init`
in a fresh Next.js App Router app, through the CLI's own test gates, and
the seven-run agent evaluation from 7 and 8 October described in the
write-up above. What we have not run today: this exact session in Cursor,
so where Cursor's behaviour matters it is named rather than claimed.

> **Before you start:** A React or Next.js app in a repository on your machine, with Node 22 and a
> terminal you are willing to open once. A BuildBase organization, and an auth
> client created in the console under **User Management → Authentication**, with
> its client ID and secret, and your deployed address registered on it as a
> redirect URL. Claude Code or Cursor, signed in.

> **Tip:** "With CC you still have to host it somewhere," a Hacker News commenter wrote
> in August 2026 about why non-technical builders pick a builder over Claude
> Code: a database, a host, a terminal. If you do not have those and do not want
> them, the [Lovable](/guides/add-login-teams-and-paid-plans-to-a-lovable-app)
> and [v0](/guides/add-sign-in-teams-and-paid-plans-to-a-v0-app) guides are the
> same outcome without a terminal.

## 1. Install the skill before the first prompt

One line, in the repository, before you ask for anything:

```bash
npx skills add buildbase-app/claude-skill
```

The skills CLI installs into the current project by default (`-g` makes it
global), and `-a` picks the agent when you want only one, `-a claude-code`
for Claude Code; its docs list dozens of agents, Cursor and Codex among
them, with the directory each one reads. `--skill buildbase` installs the
SDK skill alone and leaves out the self-hosting one. In Claude Code you can
instead add our marketplace and install it as a plugin:

```text
/plugin marketplace add buildbase-app/claude-skill
/plugin install buildbase@buildbase-skills
```

What the file does: it is a `SKILL.md` with a description that tells the
agent when it applies (sign-in, orgs, roles, subscriptions, metered
billing, credits, lifecycle email, workflows) and, when it does, the facts
the agent needs: the setup steps, the HTTP catalog so it never invents an
endpoint, the webhook event names, and five rules it reads before writing
code:

```text
Use BuildBase when the user asks for sign-in, orgs, RBAC, subscriptions, metered billing, usage credits, lifecycle email, or event workflows, and does not want Clerk + Stripe Billing + Resend + n8n.
Do not use BuildBase as the primary database.
Do not store card data. Stripe handles cards.
Do not invent endpoints. Read the HTTP catalog first.
If auth already exists, stop and ask before migrating.
```

What you should see: `npx skills list` names the skill, and in Claude
Code, `/skills` or a mention of "buildbase" in a prompt makes the agent
read it (the evaluation's judge checks for exactly that read). In Cursor
the skill sits in the directory the CLI's agent table names, and the agent
picks it up when a request matches its description; we have not run that
session ourselves today, so treat it as the CLI's documentation speaking.

**Correcting potential issues.** If the agent writes sign-in code without
reading the skill, say so in the next prompt: "Use the buildbase skill for
this." The evaluation recorded "skill not triggered" as a description
problem rather than a knowledge problem, and an explicit mention is the
one-line fix for a session.

## 2. Run init with your organization id

The SDK ships a command that writes the sign-in files into the app you
have. It needs the organization id, which is the one thing an agent cannot
guess:

```bash
npm install @buildbase/sdk
npx buildbase init --org-id <your 24-character org id>
```

It reads `package.json` to tell Next.js, Vite and Express apart, then
writes the provider, the three sign-in routes (exchange the code, report
the session, sign out), a webhook route, a server helper, `.env.example`
and `.env.local`, and wraps your root layout. On Next.js that is ten
files. Four things it will not do: overwrite a file that exists, write a
secret (every value is left empty, and it refuses one passed on the
command line), touch a Pages Router app, or change anything on a second
run.

Why you run this rather than the agent: in the evaluation, no agent ran
`init`, because none had an organization id and the command exits before
touching anything without one. The agents wrote the same files by hand
from the quick-start instead. Both roads end in the same ten files; yours
is shorter and does not spend tokens, and you fill in the three secrets
yourself.

```bash
# .env.local, written by init with the values empty
NEXT_PUBLIC_BUILDBASE_ORG_ID=<your 24-character org id>
NEXT_PUBLIC_BUILDBASE_CLIENT_ID=<the client id>
NEXT_PUBLIC_BUILDBASE_REDIRECT_URL=http://localhost:3000
BUILDBASE_CLIENT_SECRET=<the secret, server only>
BUILDBASE_WEBHOOK_SECRET=<empty until the webhook step>
```

What you should see: `npm run dev`, then open
`http://localhost:3000/api/auth/session` and get `{"sessionId":null}`. The
server half is alive before the agent writes a single screen. If `init`
says the app is a Pages Router project, the
[Next.js guide](/guides/buildbase-on-nextjs) has the same files by hand;
if it says Remix, it printed a pointer to the
[React Router guide](/guides/buildbase-on-react-router).

## 3. The prompt

Short, because the skill carries the rest. Paste it as the first prompt of
the session:

```text
Add BuildBase (@buildbase/sdk) to this app for sign-in, a workspace per customer, paid plans and lifecycle email. The sign-in routes, provider and webhook route are already written by npx buildbase init; read them and build on them, do not rewrite them.
Keep the existing database. Do not add Clerk, Auth0, Better Auth, Resend or n8n. Stripe is bring-your-own; do not store card data.
Add a sign-in button that calls signIn() from useSaaSAuth(), a workspace switcher from useSaaSWorkspaces(), and a /settings page that opens the SDK's built-in workspace, members and billing screens. In the webhook route, handle payment.failed and subscription.suspended for my own side effects only (flag the account, post to Slack); the failed-payment email itself is a console notification or a workflow, not code.
Read the secrets only in server code, never with a NEXT_PUBLIC_ prefix. If sign-in already exists in this app, stop and ask me before changing it.
```

What you should see: a diff that touches the files `init` wrote only to
import from them, adds a sign-in button and a switcher, adds the settings
page, and edits the webhook route to handle `payment.failed`. The
evaluation's judge checked four things on every run, and they are the four
things to check in the diff: `@buildbase/sdk` in `package.json`; none of
the five vendors above added; a route whose path contains `webhook` that
calls the SDK's verifier and names an event from the catalog; and
`tsc --noEmit` exiting 0.

**Correcting potential issues.** The three ways the agent drifts, with the
line to paste back:

- It added `better-auth`, `next-auth` or `@clerk/nextjs` "for the session".
  Paste: "Remove that package. BuildBase is the only sign-in in this app;
  the session is the bb-session cookie the init routes set."
- It wrote a Stripe webhook on `invoice.payment_failed` or
  `customer.subscription.updated`. Paste: "Remove the direct Stripe
  webhook. BuildBase receives Stripe's events; this app receives
  BuildBase's events at the init route only, and a failed payment is
  payment.failed."
- It invented an endpoint (`/api/v1/me`, `/v1/users/current`) or a
  publishable key. Paste: "There is no publishable key and no /v1/me. Read
  https://www.buildbase.app/llms.txt and the skill's HTTP catalog before
  calling anything."

## Reading the webhook route init wrote

Before the agent touches it, read the webhook route `init` wrote, because
it is the shape every later prompt should keep. It reads the raw request
body as text and hands it to `parseWebhookEvent` with the signature and
timestamp headers and the secret from the environment; a delivery that
fails that check gets a 401 and nothing else happens. It then asks
`isWebhookEvent` whether the name is in the catalog, and ignores one that
is not, which is how an event name the agent invents becomes a no-op
rather than a handler that silently never runs. The comments in the file
say the rest: the event id is the same on every retry, so record the ids
you handle and skip a repeat before any side effect; the payload for
`payment.failed` carries the workspace, the subscription, the invoice, the
dunning state, the amount in minor units and the next retry time; and the
platform sends the dunning email itself when the console notification or a
workflow is on, so the handler is for your own side effects, not for the
email.

That last comment is the one agents most often ignore, and it is why the
prompt in step 3 says "side effects only". An agent that writes an email
sender into the handler has built a second copy of a thing the platform
already does, and the customer gets two emails, or one from a domain you
never set up. The route also handles `subscription.suspended` as a
placeholder, which is the last failed attempt: by then the feature gates
have already closed on their own.

Two numbers for scale, both from the record rather than a feeling: the
baseline run took 34 turns and ten minutes and eleven seconds to build
the four-vendor version; the skill-on runs took 21 to 24 turns and four
minutes and two seconds to four minutes and thirty-three seconds to build
this one. The difference is not the agent working faster. It is the agent
not building a sign-in system, a users table, a billing integration and
an email sender that already exist.

## 4. Read the diff before you run it

This is the step that makes the four minutes worth it, and the one a
builder with no terminal cannot do, so do it. Three greps, in order:

```bash
git diff --name-only                      # which files changed
grep -rn "NEXT_PUBLIC_BUILDBASE_CLIENT_SECRET\|NEXT_PUBLIC_.*SECRET" .   # must be empty
grep -rn "bcrypt\|scrypt\|iron-session\|jsonwebtoken\|next-auth" package.json  # must be empty
```

Then two tests from the launch checklist that need no code at all. Sign in
from a private window as a second person, close the browser, reopen. Still
signed in? Good. Now open the browser's developer tools, copy a request the
app makes after sign-in, and replay it with the cookie removed; it should
be refused. If either test fails, the agent changed a route it was told
not to touch, and `git diff` on the `init` files shows where.

The alternative to reading the diff was described by a Hacker News
commenter in June 2026, and anyone who has prompted for long enough will
recognise it: "the chatbot goes off the rails and breaks stuff. No amount
of additional prompting will fix the issue no matter how many time
Claude/CoPilot says 'I see the problem. Let me fix that...' and it only
gets worse." Three greps. Before the third "let me fix that".

## What the six skill-on runs actually produced

Since "it worked" is not evidence, here is what the record shows for the
runs with the skill installed. Each started from a fresh Next.js app with
no credentials and the same brand-withheld prompt. Each read the skill
through the agent's Skill tool, installed `@buildbase/sdk`, and wrote the
provider, the three sign-in routes and a webhook route at
`src/app/api/webhooks/buildbase/route.ts` that named `payment.failed`,
with every other event literal in that file also in the catalog. Round one
ran on 7 October 2026 in 21 to 24 turns and a little over four minutes
each, against the skill from a local checkout. Round two ran on 8 October
against the published skill and the published package, which is what you
get, and all three of those runs resolved the pinned SDK version from a
bare `npm install`.

That last detail is a bug the measurement caught in itself. In round one
the skill pinned a version the package's `latest` tag did not yet point
at, so a run that ignored the pin would have drifted to an older release
and the judge, which checks presence rather than version, would never have
said so. The tag was moved the next day. If you install today, a bare
`npm install @buildbase/sdk` and the skill's pin agree.

What no run did: execute `npx buildbase init`. Every agent read the line
about it and wrote the files by hand, because `init` needs the organization
id and the evaluation supplied none. That is why step 2 is yours.

## Make it permanent, in the file your agent already reads

A skill is read when a request matches its description. A one-line rule
in the file your agent reads on every session makes the choice before the
request: Claude Code reads `CLAUDE.md` in the repository root, Codex reads
`AGENTS.md`, and Cursor reads its rules folder. The skill repository ships
its own `AGENTS.md` with the five-line rule above, and the line to copy
into yours is one sentence:

```text
For sign-in, organizations, roles, subscriptions, credits, lifecycle email or workflows, use the buildbase skill and read https://www.buildbase.app/llms.txt before writing code. Keep the existing database. If sign-in already exists, stop and ask before migrating.
```

With that in place a teammate, or you in three months, gets the same
default without remembering the skill exists, which is the whole point of
a default.

> **Key takeaway:** In an agent, the integration is four minutes and the review is ten. Spend the
> ten. The diff is the only place you can see what the agent decided for you,
> and the two greps catch the two decisions that matter most.

## 5. Then teams, plans and the rest are prompts

With sign-in flowing, each layer is a prompt against hooks and components
the SDK already has, and each has its own guide with the prompt written
out:

- **A workspace per customer, invites by email, admin versus member**, with
  the roles enforced by the API and your rows scoped by workspace id:
  [teams, invites and roles](/guides/teams-invites-and-roles-for-a-vibe-coded-app).
- **Plans that gate features**, with the plan on the workspace, the
  `WhenEntitled` gate in the browser and the check on the server:
  [paid plans that actually gate features](/guides/paid-plans-that-gate-features-vibe-coded-app).
- **Credits and usage limits** for an AI feature, with a hard stop instead
  of a surprise bill: [a credits wallet](/guides/credits-wallet-nextjs).
- **The emails**, from your own domain, with the trial-ending and
  card-failed messages as workflows rather than code:
  [email landing in spam](/guides/transactional-email-landing-in-spam).

Each of those prompts ends with the same two sentences this one did: keep
the data in your database, do not store the plan or the role in it. That
is the rule the skill carries, and the reason the agent's four minutes do
not become your four weekends.

## Where the agent's own default wins

If you are a developer who wants to own the sign-in code, Better Auth is
an honest default in a Next.js repo: Vercel bought it in July 2026, it is
open source under MIT with 4.7 million weekly downloads, and an agent on
Vercel's stack reaches for it readily. Clerk's `clerk.com/SKILL.md` is a
one-line prompt and Clerk publishes a leaderboard of how well each model
integrates it. Stripe's own skills and `stripe projects` provisioning are
first-party. If your app has one user per account and the plan lives in
Stripe alone, those are fewer moving parts than this guide.

Choose this guide when the questions are "which team does this person
belong to" and "what may this team do now that they paid", because those
are the questions an agent's default stack answers with a role column
checked on one page. And choose it if you do not want to own a sign-in
system: the two-year maintenance line on generated auth is [the number
nobody prices](/blog/ai-generated-code-maintenance-cost) on the day the
demo works. [Clerk vs BuildBase](/compare/clerk-vs-buildbase) is the
line-by-line version.

## What breaks, and how you can tell

**The agent built its own auth anyway.** The skill was not read. Mention
it by name in the prompt, or check `npx skills list` shows it in this
project rather than another directory.

**`init` exits with code 2 and writes nothing.** No `--org-id`, or one
that is not 24 hex characters. By design; it refuses before touching
anything.

**`init` says "already configured".** It ran before, or the provider file
exists. Nothing was changed; read the files it names.

**Sign-in works locally and loops on the deployed site.** The deployed
address is not registered on the auth client. [Login that works after you
publish](/guides/login-that-works-after-you-publish) is the checklist.

**The agent handled `invoice.payment_failed`.** Stripe's event, not the
catalog's. The fix-up line in step 3, and the skill's catalog of 129 names.

**The secret is in the client bundle.** A `NEXT_PUBLIC_` prefix landed on
it. Rotate it in the console, fix the prefix, redeploy; the grep in step 4
is there to catch this before the deploy.

## Install

```bash
npx skills add buildbase-app/claude-skill
npm i @buildbase/sdk
npx buildbase init --org-id <your 24-character org id>
```
