diff --git a/.claude/neon-terminology.md b/.claude/neon-terminology.md index 47aa237e062..fa54c0f46aa 100644 --- a/.claude/neon-terminology.md +++ b/.claude/neon-terminology.md @@ -35,7 +35,7 @@ Bare "Lakebase Postgres" is a claim about the database on **either** access path Add the qualifier when the sentence touches any of these: -- A Neon-only or Databricks-only feature (Managed Better Auth, Object Storage, Functions, AI Gateway, Data API, Claimable Postgres, Unity Catalog governance, high availability) +- A Neon-only or Databricks-only feature (Managed Better Auth, Object Storage, Functions, AI Gateway, Data API, Claimable Neon, Unity Catalog governance, high availability) - Console or UI instructions, signup, or account creation - Pricing, plans, credits, or free-tier limits - A path-specific API, CLI, SDK, Terraform provider, or MCP Server diff --git a/.env.example b/.env.example index baacfc7776a..413102c4f32 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,8 @@ NEXT_PUBLIC_GITHUB_PATH=https://github.com/neondatabase/website/tree/main/ NEXT_PUBLIC_NEON_STATUS_API=https://7687492087503394.hostedstatus.com/1.0/status/6878fc85709daa75be6c7e3c +CLAIMABLE_NEON_ORIGIN=https://claimable.neon.tech + INKEEP_ORGANIZATION_ID=neon INKEEP_INTEGRATION_ID= INKEEP_INTEGRATION_API_KEY= diff --git a/.github/workflows/agent-discovery-verify.yml b/.github/workflows/agent-discovery-verify.yml index 3534e2a87fe..9140d0d9a3f 100644 --- a/.github/workflows/agent-discovery-verify.yml +++ b/.github/workflows/agent-discovery-verify.yml @@ -24,6 +24,7 @@ on: - 'src/constants/agent-discovery.js' - 'scripts/verify-agent-endpoints.mjs' - 'src/app/.well-known/**' + - 'public/auth.md' - 'src/app/models.json/**' - 'src/app/models/**' - 'src/scripts/generate-skills-index.js' diff --git a/config/agent-endpoints.yaml b/config/agent-endpoints.yaml index 8757f47dbfb..95d4735e8dd 100644 --- a/config/agent-endpoints.yaml +++ b/config/agent-endpoints.yaml @@ -164,3 +164,21 @@ endpoints: validator: openapi check: live rewriteFile: next.config.js + + - id: claimable-authorization-server + name: Claimable Neon authorization server + description: >- + RFC 8414 metadata for the Claimable Neon path issuer on neon.com. + Token, JWKS, identity, and claim endpoints stay on claimable.neon.tech. + The protocol file is /auth.md. The apex + /.well-known/oauth-authorization-server on neon.com is unused. + servedPath: /.well-known/oauth-authorization-server/claimable + contentType: application/json + spec: + name: RFC 8414 Authorization Server Metadata + url: https://www.rfc-editor.org/rfc/rfc8414 + standard: true + validator: claimable-authorization-server + check: builder + builder: buildClaimableAuthorizationServer + routeFile: src/app/.well-known/oauth-authorization-server/claimable/route.js diff --git a/config/skills.json b/config/skills.json index 0144d22792c..d57e64f6902 100644 --- a/config/skills.json +++ b/config/skills.json @@ -2,10 +2,9 @@ "primary": "neon-postgres", "skills": [ { "name": "neon-postgres", "ref": "main" }, - { "name": "claimable-postgres", "ref": "main" }, { "name": "neon-postgres-egress-optimizer", "ref": "main" }, { "name": "neon-postgres-branches", "ref": "main" }, - { "name": "neon", "ref": "main" }, + { "name": "neon", "ref": "8a4200b2fdf8c4a5b301c717064d8aeb58c8eea5" }, { "name": "neon-postgres-agent-platforms", "ref": "main", diff --git a/content/docs/ai/agent-skills.md b/content/docs/ai/agent-skills.md index 5a4591ce79c..7ccdf3e7b55 100644 --- a/content/docs/ai/agent-skills.md +++ b/content/docs/ai/agent-skills.md @@ -143,20 +143,19 @@ Skills are grouped by area. Each skill is a `SKILL.md` entry point that your age Start here for platform overview and Postgres development. -| Skill | Description | -| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| [`neon`](https://skills.sh/neondatabase/agent-skills/neon) | Platform overview for apps and agents: Postgres, Auth, Data API, Functions, Storage, and AI Gateway, and how to get started | -| [`neon-postgres`](https://skills.sh/neondatabase/agent-skills/neon-postgres) | Full index of Neon Serverless Postgres documentation and best practices | +| Skill | Description | +| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`neon`](https://skills.sh/neondatabase/agent-skills/neon) | Platform overview for apps and agents: Postgres, Auth, Data API, Functions, Storage, and AI Gateway, including Claimable Neon when there is no account yet | +| [`neon-postgres`](https://skills.sh/neondatabase/agent-skills/neon-postgres) | Full index of Neon Serverless Postgres documentation and best practices | ### Database workflows -Provision, branch, and optimize Postgres projects. +Branch and optimize Postgres projects. -| Skill | Description | -| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| [`claimable-postgres`](https://skills.sh/neondatabase/agent-skills/claimable-postgres) | Instant temporary Postgres via [Claimable Postgres](/docs/reference/claimable-postgres), no login or credit card required | -| [`neon-postgres-branches`](https://skills.sh/neondatabase/agent-skills/neon-postgres-branches) | Choose and create the right branch type for migrations, schema-only branches, and reset-from-parent workflows | -| [`neon-postgres-egress-optimizer`](https://skills.sh/neondatabase/agent-skills/neon-postgres-egress-optimizer) | Diagnose and fix excessive Postgres egress and query overfetching | +| Skill | Description | +| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| [`neon-postgres-branches`](https://skills.sh/neondatabase/agent-skills/neon-postgres-branches) | Choose and create the right branch type for migrations, schema-only branches, and reset-from-parent workflows | +| [`neon-postgres-egress-optimizer`](https://skills.sh/neondatabase/agent-skills/neon-postgres-egress-optimizer) | Diagnose and fix excessive Postgres egress and query overfetching | ### Neon Platform @@ -198,7 +197,7 @@ With the full skill set installed, your assistant can guide you across the Neon **Database workflows** -- **Disposable databases** via Claimable Postgres for agents and tests +- **Disposable projects** via [Claimable Neon](/claimable-neon), for agents and tests - **Branch types and workflows** for migrations, schema-only branches, and reset-from-parent - **Egress optimization** for high transfer costs and query anti-patterns diff --git a/content/docs/cli/claim.md b/content/docs/cli/claim.md new file mode 100644 index 00000000000..966e4bdd25b --- /dev/null +++ b/content/docs/cli/claim.md @@ -0,0 +1,93 @@ +--- +title: 'Neon CLI command: claim' +subtitle: Create and claim a temporary Neon project without an account +summary: >- + The Neon CLI `claim` command (`neon claimable` is an alias) creates a + temporary Neon project before anyone signs in. The CLI stores an identity + assertion, writes credentials to `.env`, and later opens a claim URL so a + human can take the project. See [Claimable Neon](/docs/reference/claimable-neon). +enableTableOfContents: true +--- + +The `claim` command creates a temporary Neon project when there is no Neon account yet. `neon claimable` is an alias. The CLI stores an identity assertion on the machine, writes provisioned variables to `.env` (or `.env.local`), and later opens a claim URL so a human can take the project into their organization. + +If `neon claim` is not a command, or `neon claim --help` does not list `create`, install the latest CLI (`npm i -g neon@latest`) or use the HTTP flow in [Claimable Neon](/docs/reference/claimable-neon). + +Do not pass `--api-key` or `--profile`. Those are refused. `neon auth` and `neon init --agent` need a human Neon account; use this command instead when there is none. + +Start in the browser at [neon.com/claimable-neon](/claimable-neon), or give an agent [`auth.md`](https://neon.com/auth.md). + + + +## neon claim create (#create) + +Creates a temporary project and saves its identity assertion. Postgres is always requested. Pass `--service` for Data API, Managed Better Auth, or other services. If a [`neon.ts`](/docs/reference/neon-ts) file is present, declared services are requested automatically. + + + + + +```bash +neon claim create --env-pull +``` + +```bash +neon claim create \ + --service data-api \ + --service auth \ + --env-pull +``` + +`--env-pull` is on by default. It writes provisioned vars to an existing `.env`, otherwise `.env.local`, and gitignores that file. If `.env` or `.env.local` already has a `DATABASE_URL` (or other Neon-managed keys), pass `--file ` or `--no-env-pull`. + +After create, regular Neon CLI commands use the saved assertion. Explicit Neon account credentials take precedence when you pass them. + +## neon claim status (#status) + +Shows the linked claimable project's lifecycle and claim status. + + + + + +```bash +neon claim status +``` + +## neon claim accept (#accept) + +Creates a claim code and opens the URL where a human signs in and takes the project. `--open` is on by default. `--no-open` prints the URL. + + + + + +```bash +neon claim accept --no-open +``` + +Opening the URL does not freeze access. Continuing to Neon from that URL starts the transfer and rotates `DATABASE_URL` before the console org picker. + +## neon claim list (#list) + +Lists claimable projects saved on this machine. + + + + + +```bash +neon claim list +``` + +## neon claim delete (#delete) + +Permanently deletes the linked unclaimed project. Pass `--yes` to skip the confirmation prompt. + + + + + +```bash +neon claim delete --yes +``` diff --git a/content/docs/guides/platform-integration-overview.md b/content/docs/guides/platform-integration-overview.md index d0413d86362..716d7096edb 100644 --- a/content/docs/guides/platform-integration-overview.md +++ b/content/docs/guides/platform-integration-overview.md @@ -13,7 +13,7 @@ redirectFrom: - /docs/guides/partner-intro - /docs/guides/platform-integration-intro - /docs/guides/platform-integration-get-started -updatedOn: '2026-08-07T17:19:40.308Z' +updatedOn: '2026-08-25T17:49:33.991Z' --- Neon provides multiple options for integrating Postgres into your platform, application, or service. Choose the integration approach that best matches your use case. @@ -63,7 +63,7 @@ Use this approach when you want to create databases for your users without requi - Instant database provisioning with no user signup required - 72-hour database lifespan if not claimed - Seamless ownership transfer when users are ready -- Connection strings remain valid after claiming +- Claiming moves the project into the user's organization. neon.new keeps the connection string; Claimable Neon rotates `DATABASE_URL` - Configurable transfer request expiration **Example use cases:** @@ -79,13 +79,13 @@ Use this approach when you want to create databases for your users without requi - [TanStack](/blog/neon-joins-tanstack-instant-postgres-integration-for-faster-javascript-development): Official database partner offering instant Postgres through their Vite plugin and create-tanstack CLI - [Netlify DB](https://www.netlify.com/blog/netlify-db-database-for-ai-native-development/): One-click Postgres databases for Netlify projects, built on the claimable database flow -- [Claimable Postgres by Neon](https://neon.new/): Try instant Postgres provisioning without signup using `npx neon-new` or at [neon.new](https://neon.new/) +- [Claimable Neon](/claimable-neon): instant Neon project without signup, via the Neon CLI or [auth.md](https://neon.com/auth.md) Claimable database guide -Claimable Postgres documentation +Claimable Neon documentation diff --git a/content/docs/guides/railway.md b/content/docs/guides/railway.md index 5e174fb28e3..b7cb1572688 100644 --- a/content/docs/guides/railway.md +++ b/content/docs/guides/railway.md @@ -11,7 +11,7 @@ summary: >- Postgres, which provisions a database instantly without signup and stays claimable for 72 hours. enableTableOfContents: true -updatedOn: '2026-08-18T10:29:02.410Z' +updatedOn: '2026-08-25T17:09:07.082Z' --- [Railway](https://railway.com?utm_medium=integration&utm_source=button&utm_campaign=neon) is a cloud deployment platform that allows users to deploy anything, anywhere, seamlessly. On Railway, develop locally, connect to a repository or image, and have infrastructure provisioned automatically. Railway integrates with GitHub for continuous deployment and supports a variety of programming languages and frameworks. @@ -20,7 +20,7 @@ This guide shows how to deploy a simple Node.js application connected to a Lakeb ## Quick start alternative -If you want to get started quickly with Next.js and Lakebase Postgres on Railway, you can use the [Next.js with Neon Postgres template](https://railway.com/deploy/nextjs-with-neon-postgres?utm_medium=integration&utm_source=button&utm_campaign=neon). This template uses [Claimable Postgres by Neon](/docs/reference/claimable-postgres) to provision a database instantly without signup, perfect for rapid prototyping. The database is claimable for 72 hours, giving you time to develop before claiming it to your Neon account. +If you want to get started quickly with Next.js and Lakebase Postgres on Railway, you can use the [Next.js with Neon Postgres template](https://railway.com/deploy/nextjs-with-neon-postgres?utm_medium=integration&utm_source=button&utm_campaign=neon). That template provisions a database without signup. The current no-signup project flow is [Claimable Neon](/docs/reference/claimable-neon). Unclaimed projects expire in 72 hours. For a more detailed walkthrough using Node.js/Express with manual setup, continue with this guide below. @@ -175,6 +175,6 @@ To delete your Neon project, follow the steps outlined in the Neon documentation - [Railway platform](https://railway.com?utm_medium=integration&utm_source=button&utm_campaign=neon) - [Next.js with Neon Postgres Railway template](https://railway.com/deploy/nextjs-with-neon-postgres?utm_medium=integration&utm_source=button&utm_campaign=neon) -- [Claimable Postgres](/docs/reference/claimable-postgres) +- [Claimable Neon](/docs/reference/claimable-neon) diff --git a/content/docs/guides/tanstack-start.md b/content/docs/guides/tanstack-start.md index 0e4c04d1e42..89e65bea198 100644 --- a/content/docs/guides/tanstack-start.md +++ b/content/docs/guides/tanstack-start.md @@ -12,7 +12,7 @@ enableTableOfContents: true redirectFrom: - /docs/quickstart/tanstack-start - /docs/integrations/tanstack-start -updatedOn: '2026-08-04T05:18:26.469Z' +updatedOn: '2026-08-25T16:36:05.871Z' --- - -```bash - npm neon-new -``` - -```bash - yarn dlx neon-new -``` - -```bash - pnpm neon-new -``` - -```bash - bunx neon-new -``` - -```bash - deno run -A neon-new -``` - - +If you haven't created a project yet, [Claimable Neon](/claimable-neon) provisions a temporary Neon project without an account. A human can claim the project into a Neon account before it expires. See [Claimable Neon](/docs/reference/claimable-neon). ## Configure the Postgres client diff --git a/content/docs/introduction/roadmap.md b/content/docs/introduction/roadmap.md index 44a0fd12a83..71879368df4 100644 --- a/content/docs/introduction/roadmap.md +++ b/content/docs/introduction/roadmap.md @@ -12,7 +12,7 @@ redirectFrom: - /docs/cloud/roadmap - /docs/conceptual-guides/roadmap - /docs/reference/roadmap -updatedOn: '2026-08-24T12:09:13.878Z' +updatedOn: '2026-08-25T17:09:07.082Z' --- This roadmap describes what's in flight, what we delivered recently, and what's on the horizon. @@ -124,12 +124,12 @@ We're accelerating work on improving and scaling the core database on Neon as we - **Neon CircleCI orb**: A community-contributed orb provisions a Neon database branch per job for isolated, production-like CI. [Learn more](/docs/guides/branching-circleci). - **Add organization members by domain**: Verify email domains on the organization People page so users with matching addresses automatically join your org. [Learn more](/docs/manage/orgs-add-members-by-domain). - **TimescaleDB on Postgres 18**: The timescaledb extension is now supported on Postgres 18. [Learn more](/docs/extensions/timescaledb). -- **Claimable Postgres agent skill**: A new agent skill lets your AI assistant provision instant temporary databases via Claimable Postgres (neon.new) with no signup or credit card. [Learn more](/docs/reference/claimable-postgres). +- **Claimable Neon**: Agents can provision a temporary Neon project with no signup or credit card, then a human claims it. [Learn more](/docs/reference/claimable-neon). - **Neon MCP Server documentation tools**: The MCP Server now includes `list_docs_resources` and `get_doc_resource` so your agent can fetch Neon docs on demand. [Learn more](/docs/ai/connect-mcp-clients-to-neon). - **Compute autoscaling report**: A published report compares Neon autoscaling to provisioned compute using real production workloads, with methodology and key findings. [Learn more](https://neon.com/autoscaling-report). - **Consumption history API**: The consumption history API is now available on all paid plans. You can use it with Neon's usage-based pricing plans to track usage programmatically: query compute, storage, and data transfer at hourly, daily, or monthly granularity for custom dashboards and alerts. [Learn more](/docs/guides/consumption-metrics). - **Simpler MCP Server setup**: Configure the Neon MCP Server for all detected AI agents and editors with a single command: `npx add-mcp https://mcp.neon.tech/mcp`. OAuth opens in your browser to authorize access. For full setup (MCP plus agent skills and VS Code extension), use `npx neon@latest init`. [Learn more](/docs/ai/connect-mcp-clients-to-neon). -- **Claimable Postgres REST API**: Claimable Postgres now offers a REST API for programmatic database provisioning, making it easy to integrate Postgres into platforms, CI/CD, and automation. [Learn more](/docs/reference/claimable-postgres). +- **Claimable Neon REST API**: Claimable Neon offers an auth.md agent API for programmatic project provisioning. [Learn more](/docs/reference/claimable-neon). - **Managed Better Auth SDK simplified**: The server-side Managed Better Auth SDK for Next.js now uses a unified `createNeonAuth()` API, explicit configuration, and session caching that reduces Auth Server API calls by 95–99%. [Learn more](/docs/auth/migrate/from-auth-v0.1). - **Agent Skills**: Install [Agent Skills](https://github.com/neondatabase/agent-skills) to teach your AI assistant about Neon best practices. The Neon MCP Server can also provision the Data API with optional Managed Better Auth or external auth. [Learn more](/docs/ai/connect-mcp-clients-to-neon). - **Managed Better Auth on Vercel previews**: Both Vercel-managed and Neon-managed integrations now automatically provision Managed Better Auth on preview branches when enabled on production, so preview deployments get the right auth environment variables. [Learn more](/docs/auth/overview). @@ -163,7 +163,7 @@ We're accelerating work on improving and scaling the core database on Neon as we - **TanStack integration & new open-source tools**: Neon is now the official database partner of TanStack, with new open-source tools including a Vite Plugin for Neon to streamline fullstack development with TanStack, Vite, and Postgres. - **Data API**: Neon's Data API feature, powered by PostgREST, is open to all Neon users. [Learn more](/docs/data-api/get-started). - **Monitoring platform support**: Neon supports exporting metrics and Postgres logs to any OpenTelemetry-compatible backend, like New Relic. For details, refer to our [OpenTelemetry docs](/docs/guides/opentelemetry). -- **Claimable Postgres**: A new way for SaaS vendors to partner with Neon to offer instant Postgres databases. Let your users create Postgres databases with no registration required. [Learn more about Claimable Postgres](/docs/reference/claimable-postgres), and see our [Claimable database integration guide](/docs/workflows/claimable-database-integration). +- **Claimable Neon**: A new way for SaaS vendors to partner with Neon to offer instant Neon projects. Let your users create a project with no registration required. [Learn more about Claimable Neon](/docs/reference/claimable-neon), and see our [Claimable database integration guide](/docs/workflows/claimable-database-integration). - **Neon on Azure GA**: We've announced our general availability release on Azure with deeper Azure integration. [Read the announcement](/blog/azure-native-integration-ga). - **Import Data Assistant**: The [Import Data Assistant](/docs/import/import-data-assistant) makes data import easier and faster. - **Neon serverless driver GA**: Our JavaScript/TypeScript serverless driver has reached version 1.0.0, bringing stronger SQL injection safeguards and better performance for serverless environments. @@ -183,7 +183,7 @@ We're accelerating work on improving and scaling the core database on Neon as we - **Query monitoring in the console**: Monitor your [active queries](/docs/introduction/monitor-active-queries) and [query performance](/docs/introduction/monitor-query-performance) in the Neon Console. - **Schema-only branches**: Create branches that include only your database schema, ideal for workflows involving sensitive data. [Learn more](/docs/guides/branching-schema-only). - Support for the [postgres_fdw](/docs/extensions/postgres_fdw), [dblink](/docs/extensions/dblink), and [pg_repack](/docs/extensions/pg_repack) Postgres extensions. -- **Claimable Postgres: No signup, instant Postgres**: An app that lets you generate a Postgres database URL almost instantly, with no sign up required. Give it a try at [https://neon.new/](https://neon.new/) or by running `npx neon-new` in your terminal. See how fast Neon can spin up a Postgres database (AI agents love this). +- **Claimable Neon: No signup, instant project**: Provision a temporary Neon project with no signup, then claim it. Start at [neon.com/claimable-neon](/claimable-neon) or [`auth.md`](https://neon.com/auth.md). - **Neon Chat for Visual Studio Code**: This AI-powered assistant lets you chat with the latest Neon documentation without leaving your IDE. You can find it here: [Neon VS Code Extension](https://marketplace.visualstudio.com/items?itemName=buildwithlayer.neon-integration-expert-15j6N). - **A GitHub Copilot extension**: This extension provides chat-based access to the latest Neon documentation directly from your repository. You can find it here: [Neon Copilot Extension](https://github.com/marketplace/neon-database) - **Schema Diff API**: Neon now supports schema checks in agentic systems and deployment pipelines with the new schema diff API endpoint. Learn more about [Schema Diff](/docs/guides/schema-diff), which is also available via the console and CLI. diff --git a/content/docs/navigation.yaml b/content/docs/navigation.yaml index 100937c278e..46051f006ad 100644 --- a/content/docs/navigation.yaml +++ b/content/docs/navigation.yaml @@ -1115,11 +1115,11 @@ slug: guides/consumption-metrics - title: Query consumption metrics (legacy) slug: guides/consumption-metrics-legacy - - section: Claimable Postgres + - section: Claimable Neon icon: rocket items: - - title: Claimable Postgres - slug: reference/claimable-postgres + - title: Claimable Neon + slug: reference/claimable-neon - section: Guides icon: book items: @@ -1218,6 +1218,8 @@ slug: cli/skills - title: plugins slug: cli/plugins + - title: claim + slug: cli/claim - title: bootstrap slug: cli/bootstrap - title: link diff --git a/content/docs/reference/claimable-neon.md b/content/docs/reference/claimable-neon.md new file mode 100644 index 00000000000..2e1013859a2 --- /dev/null +++ b/content/docs/reference/claimable-neon.md @@ -0,0 +1,321 @@ +--- +title: Claimable Neon +subtitle: CLI, claim, and HTTP reference +summary: >- + If an agent needs a Neon account and the user is not around, provision a + project now; they claim it later. Agents fetch + https://neon.com/auth.md from neon.com/docs/llms.txt. +enableTableOfContents: true +redirectFrom: + - /docs/reference/neon-launchpad + - /docs/reference/instagres + - /docs/reference/claimable-postgres +updatedOn: '2026-08-25T19:29:40.470Z' +--- + +If an agent needs a Neon account and the user is not around, it provisions a project now. A human claims it later if they want to keep it. The agent receives credentials scoped to one project, builds with standard Postgres tools, and hands over a claim link. Unclaimed projects expire in 72 hours and are capped at 100 MB storage and 1 GB transfer. + +Start in the browser at [neon.com/claimable-neon](/claimable-neon), or give an agent [`auth.md`](https://neon.com/auth.md). + +## Quick start + + + + + +If `neon claim` is not a command, or `neon claim --help` does not list `create`, use the Agent API tab. + +Create a project and write its credentials to `.env`: + +```bash +neon claim create --env-pull +``` + +Request Data API or Managed Better Auth when the app needs them: + +```bash +neon claim create \ + --service data-api \ + --service auth \ + --env-pull +``` + +The CLI saves the project's identity assertion in its secure credential store. Existing commands then use the claimable project automatically: + +```bash +neon branches list +neon psql --role-name neondb_owner +``` + + + + + +An agent starts with the protocol document: + +```bash +curl https://neon.com/auth.md +``` + +Register an anonymous agent identity: + +```bash +curl --request POST https://claimable.neon.tech/v1/agent/identity \ + --header 'Content-Type: application/json' \ + --data '{ + "type": "anonymous", + "capabilities": ["postgres", "data_api"], + "source": "example-agent" + }' +``` + +The response contains an `identity_assertion`, project metadata, and one decision for every requested capability. Exchange the assertion for a short-lived access token before calling project endpoints. + + + + + +## Agent discovery + +If an agent needs a Neon account and the user is not around, [neon.com/docs/llms.txt](https://neon.com/docs/llms.txt) points at [`auth.md`](https://neon.com/auth.md). + +Claimable Neon implements [auth.md](https://workos.com/auth-md/docs/auth-md). Agents can discover the complete authentication and provisioning flow without a vendor-specific integration. + +| Document or endpoint | Purpose | +| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| `GET https://neon.com/auth.md` | Protocol file (`agent_auth.skill`) | +| `GET https://neon.com/.well-known/oauth-authorization-server/claimable` | Token, revocation, identity, and skill discovery. Issuer `https://neon.com/claimable` | +| `GET https://claimable.neon.tech/.well-known/oauth-protected-resource` | Resource server metadata | +| `GET https://claimable.neon.tech/.well-known/jwks.json` | Public keys for verifying Claimable Neon tokens | +| `POST https://claimable.neon.tech/v1/agent/identity` | Provision a project and issue a durable identity assertion | +| `POST https://claimable.neon.tech/v1/oauth2/token` | Exchange the assertion for a short-lived bearer access token | +| `POST https://claimable.neon.tech/v1/oauth2/revoke` | Revoke an access token or identity assertion | +| `GET https://claimable.neon.tech/v1/projects/{project_id}/credentials` | Read scoped project and service credentials | +| `POST https://claimable.neon.tech/v1/projects/{project_id}/claim` | Create a short-lived human claim code | +| `GET https://claimable.neon.tech/v1/projects/{project_id}/claim` | Read claim and reconciliation status | +| `DELETE https://claimable.neon.tech/v1/projects/{project_id}` | Delete an unclaimed project | +| `/v1/projects/{project_id}/...` on `claimable.neon.tech` | Use supported Neon Management API operations before claiming | + +The identity assertion is a secret. Store it like an API key. There are no refresh tokens. Exchange the assertion again when an access token expires. + +## Register and provision + +```http +POST /v1/agent/identity +Content-Type: application/json +``` + +```json +{ + "type": "anonymous", + "capabilities": ["postgres", "data_api", "auth"], + "source": "example-agent" +} +``` + +`postgres` is always requested. Add `data_api` or `auth` only when the app needs them. + +The response has this shape: + +```json +{ + "registration_id": "reg_...", + "identity_assertion": "eyJ...", + "project": { + "id": "quiet-fog-12345678", + "branch_id": "br-...", + "expires_at": "2026-08-14T12:00:00.000Z" + }, + "capabilities": [ + { + "capability": "postgres", + "granted": true, + "scopes": ["postgres.read", "postgres.write"] + }, + { + "capability": "data_api", + "granted": true, + "scopes": ["data_api.query"] + } + ] +} +``` + +Check every capability decision. A successful registration can contain denied optional capabilities. + +### Exchange the identity assertion + +```bash +curl --request POST https://claimable.neon.tech/v1/oauth2/token \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \ + --data-urlencode 'assertion=YOUR_IDENTITY_ASSERTION' \ + --data-urlencode 'resource=https://claimable.neon.tech/' +``` + +The response contains a bearer `access_token`, its scope, and its expiration: + +```json +{ + "access_token": "eyJ...", + "token_type": "Bearer", + "expires_in": 900, + "scope": "postgres.read postgres.write data_api.query" +} +``` + +### Pull credentials + +```bash +curl https://claimable.neon.tech/v1/projects/quiet-fog-12345678/credentials \ + --header "Authorization: Bearer $ACCESS_TOKEN" +``` + +```json +{ + "project_id": "quiet-fog-12345678", + "branch_id": "br-...", + "database_url": "postgresql://neondb_owner:...@ep-...-pooler.../neondb?sslmode=require", + "expires_at": "2026-08-14T12:00:00.000Z", + "services": { + "data_api": { + "url": "https://ep-....apirest.c-2.us-east-2.aws.neon.tech/neondb/rest/v1" + }, + "auth": { + "base_url": "https://ep-....neonauth.c-2.us-east-2.aws.neon.tech/api/auth", + "jwks_url": "https://ep-....neonauth.c-2.us-east-2.aws.neon.tech/.well-known/jwks.json" + } + } +} +``` + +Only requested and granted services appear under `services`. + +## Capabilities + +| Capability | Available before claim | Environment variable | +| ------------------- | ---------------------- | ----------------------------- | +| Postgres | Yes | `DATABASE_URL` | +| Data API | When requested | `NEON_DATA_API_URL` | +| Managed Better Auth | When requested | `NEON_AUTH_BASE_URL` | +| Functions | No | Requires claiming the project | +| Object Storage | No | Requires claiming the project | +| AI Gateway | No | Requires claiming the project | + +Registration records those as `{ granted: false, reason: "requires_claim" }`. A later protected operation returns `capability_requires_claim`. Preserve the denied capability and give the human a claim link; do not retry or drop it. + +## Use the Neon CLI + +`neon claim` and its `neon claimable` alias manage anonymous projects. If `neon claim` is not a command, or `neon claim --help` does not list `create`, use the HTTP flow in this page. + +```bash +neon claim create --env-pull + +neon claim create --service data-api --service auth --env-pull + +neon claim status + +neon claim accept --no-open + +neon claim list + +neon claim delete --yes +``` + +`neon claim accept` opens a browser by default. `--no-open` prints the URL for a human to open. + +After `claim create`, regular Neon CLI commands exchange the saved identity assertion and route supported management operations through Claimable Neon. Explicit Neon account credentials take precedence when you pass them. + +If a `neon.ts` file is present, `claim create` requests its declared services automatically: + +```typescript filename="neon.ts" +import { defineConfig } from '@neon/config/v1'; + +export default defineConfig({ + auth: true, + dataApi: true, +}); +``` + +Services that require human ownership still run through normal Config-as-Code planning. Claimable Neon returns `capability_requires_claim` for those operations, so the agent can ask for a claim instead of silently omitting part of the configuration. + +## Claim a project + +Create a claim code with the API: + +```bash +curl --request POST \ + https://claimable.neon.tech/v1/projects/quiet-fog-12345678/claim \ + --header "Authorization: Bearer $ACCESS_TOKEN" +``` + +```json +{ + "user_code": "ABCD-2345", + "verification_uri": "https://claimable.neon.tech/claim", + "verification_uri_complete": "https://claimable.neon.tech/claim?user_code=ABCD-2345", + "expires_in": 900, + "interval": 5 +} +``` + +Open `verification_uri_complete` and sign in to Neon. Opening the URL does not freeze access. Continuing to Neon starts the transfer: it revokes the project key, access tokens, and database password before the console transfer URL is shown. Auth and the Data API stay enabled and transfer with the project. Choose the destination organization. The project then moves through these states: + +1. `pending`: the claim code exists, but the transfer has not completed. +2. `accepted`: the project has left the unclaimed-project organization. +3. `reconciled`: the identity assertion is revoked and the ceremony is finished. + +Continuing to Neon revokes existing access tokens. Re-exchange the identity assertion, then poll claim status at the server-provided `interval`. The new token is only good for that poll until `reconciled`. + +```bash +curl --request POST https://claimable.neon.tech/v1/oauth2/token \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \ + --data-urlencode "assertion=$IDENTITY_ASSERTION" \ + --data-urlencode 'resource=https://claimable.neon.tech/' + +curl https://claimable.neon.tech/v1/projects/quiet-fog-12345678/claim \ + --header "Authorization: Bearer $ACCESS_TOKEN" +``` + +Only `reconciled` means the assertion is dead. Use credentials from the destination Neon organization after that. Fetch a new `DATABASE_URL` there; Auth and the Data API keep working. + +## Errors + +Errors use one JSON shape across provisioning, token, credential, and management endpoints: + +```json +{ + "error": { + "code": "capability_requires_claim", + "origin": "proxy", + "message": "Functions require claiming this project.", + "retryable": false, + "request_id": "req_..." + } +} +``` + +Use `error.code` for control flow and show `error.message` to the user. Retry only when `retryable` is `true`. + +Common codes include: + +| Code | Meaning | +| --------------------------- | ------------------------------------------------------------ | +| `invalid_request` | The request body or parameter is invalid | +| `invalid_grant` | The identity assertion cannot be exchanged. Discard it | +| `unauthorized` | No credential was presented, or it did not verify | +| `token_expired` | The access token expired. Re-exchange the identity assertion | +| `scope_insufficient` | The access token does not permit the operation | +| `capability_requires_claim` | The requested service or operation requires human ownership | +| `claim_in_progress` | Only claim-status polling remains available | +| `project_claimed` | The project transferred. Discard the identity assertion | +| `project_expired` | The unclaimed window closed. Discard the identity assertion | +| `upstream_error` | A Neon API or service dependency failed | + +## Resources + +- [Create a project in the browser](/claimable-neon) +- [Claimable Neon auth.md](https://neon.com/auth.md) +- [Neon CLI reference](/docs/cli) +- [Claimable database integration](/docs/workflows/claimable-database-integration) diff --git a/content/docs/reference/claimable-postgres.md b/content/docs/reference/claimable-postgres.md deleted file mode 100644 index ef4aaa7796b..00000000000 --- a/content/docs/reference/claimable-postgres.md +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: Claimable Postgres by Neon -subtitle: Launch an instant Lakebase Postgres database on Neon with zero configuration -summary: >- - Claimable Postgres provisions an instant database via a single - unauthenticated API call, CLI command, Node.js SDK, or Vite plugin with no - account required. Unclaimed databases expire after 72 hours and are capped - at 100 MB storage and 1 GB transfer. Claiming to a Neon account removes - expiration and raises limits to the Free plan. Use this page for the REST - API reference, neon-new CLI options, and SDK integration for building - instant-database or launchpad experiences. -enableTableOfContents: true -redirectFrom: - - /docs/reference/neon-launchpad - - /docs/reference/instagres -updatedOn: '2026-08-04T05:05:30.414Z' ---- - -Claimable Postgres gives you an instant Postgres database with a single API call. No account required. - -Your database expires after 72 hours unless you claim it to your Neon account. Databases are provisioned on AWS us-east-2 running Postgres 17. - -Access it at [neon.new](https://neon.new/). - -## Quick start - - - - - -```bash -curl -X POST https://neon.new/api/v1/database \ - -H 'Content-Type: application/json' \ - -d '{"ref": "your-app-name"}' -``` - -Example response: - -```json -{ - "id": "01abc123-def4-5678-9abc-def012345678", - "status": "UNCLAIMED", - "neon_project_id": "cool-breeze-12345678", - "connection_string": "postgresql://neondb_owner:npg_xxxx@ep-cool-breeze-pooler...", - "claim_url": "https://neon.new/claim/01abc123-def4-5678-9abc-def012345678", - "expires_at": "2026-02-01T12:00:00.000Z", - "created_at": "2026-01-29T12:00:00.000Z", - "updated_at": "2026-01-29T12:00:00.000Z" -} -``` - -See [API reference](#api) for details. - - - - - -```bash -npx neon-new --yes -``` - -Writes to your `.env` file (partial output): - -``` -DATABASE_URL=postgresql://neondb_owner:npg_xxxxxxxxxxxx@ep-cool-breeze-a1b2c3d4-pooler.c-2.us-east-2.aws.neon.tech/neondb?channel_binding=require&sslmode=require -``` - -See [CLI reference](#command-line-interface) for details. - - - - - -## Limits - -Unclaimed databases have stricter quotas. Claiming resets limits to your Neon plan. - -| | Unclaimed | Claimed (Free plan) | -| ---------- | --------- | ------------------- | -| Storage | 100 MB | 512 MB | -| Transfer | 1 GB | ~5 GB | -| Branches | No | Yes | -| Expiration | 72 hours | None | - -## Claiming a database - -Claiming is **optional**. Your database works immediately. Claim only if you want to keep it beyond 72 hours. - -**To claim:** - -1. Visit the `claim_url` from the API response -2. Sign in to Neon (or create an account) -3. Choose an organization for the database -4. Complete the transfer - -After claiming, the database appears in your Neon console with expiration removed. The `status` changes to `CLAIMED` and `connection_string` becomes `null` in the API (use Neon console instead). - -## API - -The Claimable Postgres API provides programmatic database provisioning. No authentication required. - -**Base URL:** `https://neon.new/api/v1` - -### Create database - -``` -POST /api/v1/database -``` - -| Parameter | Required | Description | -| ---------------------------- | -------- | ------------------------------------------- | -| `ref` | Yes | Referrer identifier (for tracking) | -| `enable_logical_replication` | No | Enable logical replication (default: false) | - -### Get database - -``` -GET /api/v1/database/:id -``` - -Returns the same response schema. - -### Response fields - -| Field | Type | Description | -| ------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- | -| `id` | string | Database identifier (UUID v7) | -| `status` | string | `UNCLAIMED`, `CLAIMING`, or `CLAIMED` | -| `neon_project_id` | string | Underlying Neon project ID | -| `connection_string` | string \| null | Postgres connection URL with pooling (null after claimed). For direct connections, remove `-pooler` from the hostname. | -| `claim_url` | string | URL to claim the database | -| `expires_at` | string | ISO 8601 expiration timestamp | -| `created_at` | string | ISO 8601 creation timestamp | -| `updated_at` | string | ISO 8601 last update timestamp | - -
-Error responses - -| Condition | HTTP | Message | -| ---------------------- | ---- | ------------------------------------ | -| Missing or empty `ref` | 400 | `Missing referrer` (includes `hint`) | -| Invalid database ID | 400 | `Database not found` | -| Invalid JSON body | 500 | `Failed to create the database.` | -| Invalid parameter type | 500 | `Failed to create the database.` | - -
- -## Command-line interface - -The `neon-new` CLI creates a database and writes credentials to your `.env` file: - - - - -```bash -npx neon-new -``` - - -```bash -yarn dlx neon-new -``` - - -```bash -pnpm dlx neon-new -``` - - -```bash -bunx neon-new -``` - - -```bash -deno run -A neon-new -``` - - - -**Options:** - -| Option | Alias | Description | Default | -| ----------------------- | ----- | ------------------------------------- | -------------- | -| `--yes` | `-y` | Skip prompts and use defaults | | -| `--env ` | `-e` | Path to the .env file | `./.env` | -| `--key ` | `-k` | Env var for connection string | `DATABASE_URL` | -| `--prefix ` | `-p` | Prefix for generated public vars | `PUBLIC_` | -| `--seed ` | `-s` | Path to SQL file to seed the database | | -| `--logical-replication` | `-L` | Enable logical replication | `false` | -| `--ref ` | `-r` | Referrer ID for affiliates program | | -| `--help` | `-h` | Show help message | | - -**Example output in `.env`:** - -```txt -DATABASE_URL=postgresql://neondb_owner:npg_xxxxxxxxxxxx@ep-cool-breeze-a1b2c3d4-pooler.c-2.us-east-2.aws.neon.tech/neondb?channel_binding=require&sslmode=require -DATABASE_URL_DIRECT=postgresql://neondb_owner:npg_xxxxxxxxxxxx@ep-cool-breeze-a1b2c3d4.c-2.us-east-2.aws.neon.tech/neondb?channel_binding=require&sslmode=require -# Claimable DB expires at: Sat, 01 Feb 2026 12:00:00 GMT -# Claim it now to your account using the link below: -PUBLIC_POSTGRES_CLAIM_URL=https://neon.new/claim/01abc123-def4-5678-9abc-def012345678 -``` - -- `DATABASE_URL` is a pooled connection (hostname contains `-pooler`). Use this for application queries. -- `DATABASE_URL_DIRECT` is a direct connection (no pooler). Use this for migrations (e.g. Prisma). - -To claim, visit the URL in the comments above or run `npx neon-new claim` to open it in your browser. - -## SDK - -The `neon-new` package also exports an SDK for programmatic provisioning in Node.js scripts: - -```javascript -import { instantPostgres } from 'neon-new'; - -const { databaseUrl, databaseUrlDirect, claimUrl, claimExpiresAt } = await instantPostgres({ - referrer: 'your-app-name', -}); -``` - -The `referrer` parameter is required. The function returns: - -| Field | Type | Description | -| ------------------- | ------ | --------------------------------------------------- | -| `databaseUrl` | string | Pooled connection URL (use for application queries) | -| `databaseUrlDirect` | string | Direct connection URL (use for migrations) | -| `claimUrl` | string | URL to claim the database to a Neon account | -| `claimExpiresAt` | Date | Expiration timestamp as a JavaScript Date object | - -You can also pass a seed option to run SQL on creation: - -```javascript -const result = await instantPostgres({ - referrer: 'your-app-name', - seed: { type: 'sql-script', path: './schema.sql' }, -}); -``` - -## Vite plugin - -Add automatic database provisioning to Vite projects with `vite-plugin-neon-new`: - -```bash -npm install -D vite-plugin-neon-new -``` - -```js -import { postgres } from 'vite-plugin-neon-new'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - plugins: [ - postgres({ referrer: 'your-app-name' }), - ], -}); -``` - -The plugin provisions a database on first `vite dev` if `DATABASE_URL` is missing. It's inactive during `vite build`. - -**Additional options:** - -```js -// Inside defineConfig({ plugins: [...] }) -postgres({ - referrer: 'your-app-name', // Required - dotEnvFile: '.env.local', // Default: .env - dotEnvKey: 'DATABASE_URL', // Default: DATABASE_URL - envPrefix: 'VITE_', // For public env vars - seed: { - type: 'sql-script', - path: './schema.sql', - }, -}) -``` - -## Resources - -- [Claimable Postgres website](https://neon.new/) -- [neon-new CLI on GitHub](https://github.com/neondatabase/neondb-cli/tree/main/packages/neon-new) -- [Vite Plugin on GitHub](https://github.com/neondatabase/neondb-cli/tree/main/packages/vite-plugin-neon-new) -- [Claimable database integration](/docs/workflows/claimable-database-integration) (build your own claimable Postgres experience) diff --git a/content/docs/workflows/claimable-database-integration.md b/content/docs/workflows/claimable-database-integration.md index bf3cafc9c49..a53d852b1ee 100644 --- a/content/docs/workflows/claimable-database-integration.md +++ b/content/docs/workflows/claimable-database-integration.md @@ -10,7 +10,7 @@ summary: >- creation. The feature is in private preview and does not support transferring projects into Vercel-managed Neon organizations. enableTableOfContents: true -updatedOn: '2026-07-15T00:58:07.525Z' +updatedOn: '2026-08-25T16:36:05.871Z' --- ## Overview @@ -242,7 +242,7 @@ Without the `org_id` parameter, the project transfers to the user's personal acc - **Demo environments** - Create ready-to-use demo databases that prospects can claim - **Team environments** - Provision project databases for team members to claim into their organization -For a working implementation of claimable databases, try [Claimable Postgres by Neon](https://neon.new/). This service demonstrates the complete flow: users receive a Postgres connection string immediately without creating an account, and databases remain active for 72 hours. To retain the database beyond this period, users claim it by creating a Neon account using the provided transfer URL. See the [Claimable Postgres documentation](/docs/reference/claimable-postgres) for implementation details. This same pattern enables SaaS providers to offer instant database provisioning while allowing users to take ownership when ready. +For a working implementation, try [Claimable Neon](/claimable-neon). Agents fetch [`auth.md`](https://neon.com/auth.md), receive project-scoped credentials, and hand a claim link to a human. The registration response provides the project expiration time. See the [Claimable Neon reference](/docs/reference/claimable-neon) for CLI commands. ## Troubleshooting diff --git a/content/faqs/databases-instantly-spin-up-postgres-instance.md b/content/faqs/databases-instantly-spin-up-postgres-instance.md index c232cbf3cb0..2e84fe9519f 100644 --- a/content/faqs/databases-instantly-spin-up-postgres-instance.md +++ b/content/faqs/databases-instantly-spin-up-postgres-instance.md @@ -32,7 +32,7 @@ The last command prints a Postgres connection string you can pass to any driver. For automated provisioning, the [Neon API](/docs/reference/api) creates a project, branch, and compute in one call. This is how platforms like Vercel and Replit spin up a per-user database the moment someone signs up. -If you don't want to sign up at all, [Claimable Postgres](https://neon.new) gives you a working database in seconds without an account. Run `npx neon-new --yes` and you get a connection string that's valid for 72 hours. Claim it to a Neon account before it expires to keep it. +If you don't want to sign up at all, [Claimable Neon](https://neon.com/claimable-neon) gives you a working project in seconds without an account. Claim it to a Neon account before it expires to keep it. See the [Claimable Neon docs](https://neon.com/docs/reference/claimable-neon.md). ## What you get on the Free plan diff --git a/content/guides/isolated-subagents-neon-branching.md b/content/guides/isolated-subagents-neon-branching.md index 60e8baa5e2a..6a04f678c72 100644 --- a/content/guides/isolated-subagents-neon-branching.md +++ b/content/guides/isolated-subagents-neon-branching.md @@ -4,7 +4,7 @@ subtitle: 'Automate parallel feature development by giving every Claude Code sub author: dhanush-reddy enableTableOfContents: true createdAt: '2026-03-03T00:00:00.000Z' -updatedOn: '2026-06-11T23:50:21.258Z' +updatedOn: '2026-08-13T16:00:41.084Z' --- While modern AI assistants generate code at remarkable speeds, the development process often remains sequential. You ask an agent to build a feature and wait. You request a query optimization and wait again. This workflow is bottlenecked by the linear nature of the standard AI interface, which can only run one agent at a time, completing one task before starting the next. @@ -34,7 +34,7 @@ To demonstrate this in action, a social media application built with Next.js and Before you begin, ensure you have the following: - **Claude Code:** Anthropic's official CLI tool installed. Visit [Claude code docs](https://code.claude.com/docs/en/quickstart#step-1-install-claude-code) for installation instructions. -- **Neon account and project:** A Neon account with an active project. Sign up at [neon.new](https://neon.new). +- **Neon account and project:** A Neon account with an active project. Sign up at [neon.com](https://console.neon.tech). - The [Neon CLI](/docs/cli) installed (`npm i -g neon` or `brew install neonctl`). - **Example application with Git repository**: Any application with a Git repository. This guide uses a Next.js app with Drizzle ORM (a simple social media app) as an example, but you can follow along with your own codebase. The emphasis here is on demonstrating the parallel workflow rather than the specifics of the application. diff --git a/content/pages/platforms.md b/content/pages/platforms.md index bcd0338462a..21ee4ffcecb 100644 --- a/content/pages/platforms.md +++ b/content/pages/platforms.md @@ -154,7 +154,7 @@ _Netlify DB provisioning a Postgres database from a Netlify project, powered by - [Platform integration overview: claimable database flow](/docs/guides/platform-integration-overview#claimable-database-flow) - when this path fits vs embedded Postgres, OAuth, or the Agent plan - [Claimable database integration guide](/docs/workflows/claimable-database-integration) - create a project, issue a transfer request, and hand off ownership -- [Claimable Postgres](/docs/reference/claimable-postgres) - reference for the neon.new instant-database flow +- [Claimable Neon](/docs/reference/claimable-neon) - reference for the claimable Neon project flow diff --git a/content/pages/use-cases/ai-agents.md b/content/pages/use-cases/ai-agents.md index 2009e7015c6..73e26da824d 100644 --- a/content/pages/use-cases/ai-agents.md +++ b/content/pages/use-cases/ai-agents.md @@ -126,4 +126,4 @@ For instructions on using the Neon API to provision and manage backends on behal To learn more about the Agent Plan, [see the details on this page](https://neon.com/programs/agents#agent-plan-pricing) or [fill out the application form directly, at the top of this page](#agent-form). - + diff --git a/next.config.js b/next.config.js index 8db78e5c7a5..fc69040f68a 100644 --- a/next.config.js +++ b/next.config.js @@ -2304,14 +2304,84 @@ const defaultConfig = { }, { source: '/launchpad', - destination: 'https://neon.new', + destination: '/claimable-neon', permanent: false, }, { source: '/instagres', - destination: 'https://neon.new', + destination: '/claimable-neon', permanent: false, }, + { + source: '/claimable', + destination: '/claimable-neon', + permanent: false, + }, + { + source: '/claimable-postgres', + destination: '/claimable-neon', + permanent: true, + }, + { + source: '/docs/reference/claimable-postgres', + destination: '/docs/reference/claimable-neon', + permanent: true, + }, + { + source: '/docs/reference/claimable-postgres.md', + destination: '/docs/reference/claimable-neon.md', + permanent: true, + }, + { + source: '/docs/ai/skills/claimable-postgres', + destination: '/auth.md', + permanent: true, + }, + { + source: '/docs/ai/skills/claimable-postgres/:path*', + destination: '/auth.md', + permanent: true, + }, + { + source: '/.well-known/agent-skills/claimable-postgres', + destination: '/auth.md', + permanent: true, + }, + { + source: '/.well-known/agent-skills/claimable-postgres/:path*', + destination: '/auth.md', + permanent: true, + }, + { + source: '/.well-known/skills/claimable-postgres', + destination: '/auth.md', + permanent: true, + }, + { + source: '/.well-known/skills/claimable-postgres/:path*', + destination: '/auth.md', + permanent: true, + }, + { + source: '/docs/.well-known/agent-skills/claimable-postgres', + destination: '/auth.md', + permanent: true, + }, + { + source: '/docs/.well-known/agent-skills/claimable-postgres/:path*', + destination: '/auth.md', + permanent: true, + }, + { + source: '/docs/.well-known/skills/claimable-postgres', + destination: '/auth.md', + permanent: true, + }, + { + source: '/docs/.well-known/skills/claimable-postgres/:path*', + destination: '/auth.md', + permanent: true, + }, { source: '/docs/local/neon-local-vscode', destination: '/docs/local/neon-local-connect', diff --git a/public/.well-known/agent-skills/index.json b/public/.well-known/agent-skills/index.json index dd7cdc73963..00fa86d79fc 100644 --- a/public/.well-known/agent-skills/index.json +++ b/public/.well-known/agent-skills/index.json @@ -8,13 +8,6 @@ "url": "/.well-known/agent-skills/neon-postgres/SKILL.md", "digest": "sha256:eb8081a09e25ff2062e8f8de7cba00c38123aeb259771605c988ca0245389886" }, - { - "name": "claimable-postgres", - "type": "skill-md", - "description": "Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and SDK. Use when users ask for a quick Postgres environment, a throwaway DATABASE_URL for prototyping/tests, or \"just give me a DB now\". Triggers include: \"quick postgres\", \"temporary postgres\", \"no signup database\", \"no credit card database\", \"instant DATABASE_URL\", \"npx neon-new\", \"neon.new\", \"neon.new API\", \"claimable postgres API\".", - "url": "/.well-known/agent-skills/claimable-postgres/SKILL.md", - "digest": "sha256:54af158fccb7412ce0e00ce136c2f7e23fcf173670db84224c445f254d902b41" - }, { "name": "neon-postgres-egress-optimizer", "type": "skill-md", @@ -32,16 +25,16 @@ { "name": "neon", "type": "skill-md", - "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\".", + "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\". Also use when there is no Neon account yet, the user cannot sign in or provide an API key right now and needs a project they can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup database, temporary postgres, quick postgres, a no credit card database, or npx neon-new.", "url": "/.well-known/agent-skills/neon/SKILL.md", - "digest": "sha256:2288231fb0aaeedae21eb77762dcb44ced134d0b9e241404f2c6c35a6c2e4a5b" + "digest": "sha256:9e3aafe76e94c6dba997e164ff0a9d51431f79b04ecd36d78ae41d7ef1333bfe" }, { "name": "neon-postgres-agent-platforms", "type": "skill-md", - "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", + "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", "url": "/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", - "digest": "sha256:167e52b3c75f41b479a10a731ca2dd8729eec5f9f597d5a589a576a044345499" + "digest": "sha256:bba13ea7bf219fd7db71198785096bec92f43579b6def3281d077d3226228a5c" }, { "name": "neon-object-storage", diff --git a/public/.well-known/skills/index.json b/public/.well-known/skills/index.json index bffabb82d5f..f97091c222e 100644 --- a/public/.well-known/skills/index.json +++ b/public/.well-known/skills/index.json @@ -7,13 +7,6 @@ "SKILL.md" ] }, - { - "name": "claimable-postgres", - "description": "Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and SDK. Use when users ask for a quick Postgres environment, a throwaway DATABASE_URL for prototyping/tests, or \"just give me a DB now\". Triggers include: \"quick postgres\", \"temporary postgres\", \"no signup database\", \"no credit card database\", \"instant DATABASE_URL\", \"npx neon-new\", \"neon.new\", \"neon.new API\", \"claimable postgres API\".", - "files": [ - "SKILL.md" - ] - }, { "name": "neon-postgres-egress-optimizer", "description": "Diagnose and fix excessive Postgres egress (network data transfer) in a codebase. Use when a user mentions high database bills, unexpected data transfer costs, network transfer charges, egress spikes, \"why is my Neon bill so high\", \"database costs jumped\", SELECT * optimization, query overfetching, reduce Neon costs, optimize database usage, or wants to reduce data sent from their database to their application. Also use when reviewing query patterns for cost efficiency, even if the user doesn't explicitly mention egress or data transfer.", @@ -30,14 +23,14 @@ }, { "name": "neon", - "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\".", + "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\". Also use when there is no Neon account yet, the user cannot sign in or provide an API key right now and needs a project they can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup database, temporary postgres, quick postgres, a no credit card database, or npx neon-new.", "files": [ "SKILL.md" ] }, { "name": "neon-postgres-agent-platforms", - "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", + "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", "files": [ "SKILL.md" ] diff --git a/public/auth.md b/public/auth.md new file mode 100644 index 00000000000..901c4e59029 --- /dev/null +++ b/public/auth.md @@ -0,0 +1,170 @@ +# Claimable Neon for agents + +If you need a Neon account and the user is not around, provision a project now. A human claims it +later if they want to keep it. + +Claimable Neon issues an identity assertion and credentials scoped to one project. + +## Discover + +Start at `llms.txt`, then this document. Do not guess `POST /v1/agent/identity`. + +```text +https://neon.com/docs/llms.txt +https://neon.com/auth.md +https://neon.com/.well-known/oauth-authorization-server/claimable +https://claimable.neon.tech/.well-known/oauth-protected-resource +https://claimable.neon.tech/.well-known/jwks.json +``` + +`agent_auth.skill` is this file. `identity_endpoint` is where you register. `claim_endpoint` +accepts `{"claim_token":""}`. JWT `iss` is `https://neon.com/claimable`. Token +`aud` / `resource` is `https://claimable.neon.tech/`. Request and response field names for the +HTTP calls below also live at `https://claimable.neon.tech/auth.md`. If this file and that file +disagree on a field, use that copy. Token exchange, JWKS, and project REST stay on +`https://claimable.neon.tech`. + +## Install the Neon CLI + +The Neon CLI is the client. Do not start from the HTTP examples unless you are implementing a +client. Install it. If `NEON_API_KEY` is set, or `neon profile list -o json` +lists a profile whose `account` is not `-`, use that account and stop. A `DEFAULT` row with +`account: "-"` and `file: "missing"` is not an account. If a command waits on a browser or +authentication fails, stop and ask the user to sign in (`neon auth`) or mint an API key. Do not +run `neon auth` on this path. + +If there is no account, declare services in `neon.ts`, and let the CLI register, store the identity +assertion, and pull env. + +```bash +npm i -g neon@latest +neon skills -s neon -s neon-postgres +``` + +https://neon.com/docs/cli/install.md +https://neon.com/docs/reference/neon-ts.md + +```bash +neon claim create --service data-api --service auth --env-pull +neon branches list +``` + +If `neon claim` is not a command, or `neon claim --help` does not list `create`, use the HTTP +below. The HTTP below is the protocol the CLI speaks. + +## Register anonymously + +Request `postgres` and any optional services the app needs. `data_api` and `auth` are +available before claim. `functions`, `storage`, and `ai_gateway` return a recorded +`reason: "requires_claim"` decision. Calling a protected operation for one of those capabilities +returns the `capability_requires_claim` error code. + +```http +POST https://claimable.neon.tech/v1/agent/identity +Content-Type: application/json + +{"type":"anonymous","capabilities":["postgres","data_api","auth"],"source":"your-agent"} +``` + +The response contains: + +- `identity_assertion`: the durable secret. Store it like an API key. +- `project.id`, `project.branch_id`, and `project.expires_at`. +- One decision for every requested capability. Check `granted` before using a service. + +## Exchange for an access token + +```http +POST https://claimable.neon.tech/v1/oauth2/token +Content-Type: application/x-www-form-urlencoded + +grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=&resource=https://claimable.neon.tech/ +``` + +The response contains a short-lived bearer `access_token` and no refresh token. Re-exchange the +identity assertion when the access token expires. + +## Pull credentials + +```http +GET https://claimable.neon.tech/v1/projects//credentials +Authorization: Bearer +``` + +The response contains `database_url`, the project and branch IDs, `expires_at`, and credentials +for granted services: + +- `services.data_api.url` +- `services.auth.base_url` +- `services.auth.jwks_url` + +## Use the project + +Use `database_url` with any Postgres client. Supported Neon Management API operations are +available through the scoped proxy: + +```http +GET https://claimable.neon.tech/v1/projects//... +Authorization: Bearer +``` + +The project-scoped Neon API key stays inside Claimable Neon and is never returned. + +## Claim the project + +Metadata `claim_endpoint` is `POST /v1/agent/identity/claim` with `{"claim_token":""}`. +The HTTP below uses the access token instead. Both create the same claim code. + +Create a short-lived human claim code when the project is ready to keep: + +```http +POST https://claimable.neon.tech/v1/projects//claim +Authorization: Bearer +``` + +Open the returned `verification_uri_complete`. Opening the URL does not freeze access. Continuing +to Neon starts the transfer and rotates `DATABASE_URL`. The human signs in to Neon, selects a +destination organization, and accepts the transfer. + +Continuing to Neon revokes existing access tokens. Re-exchange the identity assertion; while the +claim is in progress, the new token has no project scopes and authorizes only claim-status polling: + +```http +POST https://claimable.neon.tech/v1/oauth2/token +Content-Type: application/x-www-form-urlencoded + +grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=&resource=https://claimable.neon.tech/ +``` + +Retain that access token and poll at the returned `interval`: + +```http +GET https://claimable.neon.tech/v1/projects//claim +Authorization: Bearer +``` + +The claim moves through `pending`, `accepted`, and `reconciled`. Stop using pre-claim +credentials when the browser claim starts. At `reconciled`, the identity assertion, access +tokens, project key, and database password no longer authorize project access. Auth and the +Data API stay enabled and transfer with the project. The status endpoint keeps returning the +terminal `reconciled` state when retried with the retained status token. + +## Delete or revoke + +Delete an unclaimed project: + +```http +DELETE https://claimable.neon.tech/v1/projects/ +Authorization: Bearer +``` + +Revoke an access token or identity assertion with `POST https://claimable.neon.tech/v1/oauth2/revoke`. + +## Handle errors + +Every error has an `error.code`, human-readable `error.message`, `error.origin`, +`error.retryable`, and `error.request_id`. Use the code for control flow. Retry only when +`error.retryable` is true. + +When `error.code` is `capability_requires_claim`, preserve the denied capability and give the +human a claim link instead of retrying or silently omitting it. diff --git a/public/docs/.well-known/agent-skills/index.json b/public/docs/.well-known/agent-skills/index.json index 562f9d976fa..fd614178f32 100644 --- a/public/docs/.well-known/agent-skills/index.json +++ b/public/docs/.well-known/agent-skills/index.json @@ -8,13 +8,6 @@ "url": "/docs/.well-known/agent-skills/neon-postgres/SKILL.md", "digest": "sha256:eb8081a09e25ff2062e8f8de7cba00c38123aeb259771605c988ca0245389886" }, - { - "name": "claimable-postgres", - "type": "skill-md", - "description": "Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and SDK. Use when users ask for a quick Postgres environment, a throwaway DATABASE_URL for prototyping/tests, or \"just give me a DB now\". Triggers include: \"quick postgres\", \"temporary postgres\", \"no signup database\", \"no credit card database\", \"instant DATABASE_URL\", \"npx neon-new\", \"neon.new\", \"neon.new API\", \"claimable postgres API\".", - "url": "/docs/.well-known/agent-skills/claimable-postgres/SKILL.md", - "digest": "sha256:54af158fccb7412ce0e00ce136c2f7e23fcf173670db84224c445f254d902b41" - }, { "name": "neon-postgres-egress-optimizer", "type": "skill-md", @@ -32,16 +25,16 @@ { "name": "neon", "type": "skill-md", - "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\".", + "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\". Also use when there is no Neon account yet, the user cannot sign in or provide an API key right now and needs a project they can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup database, temporary postgres, quick postgres, a no credit card database, or npx neon-new.", "url": "/docs/.well-known/agent-skills/neon/SKILL.md", - "digest": "sha256:2288231fb0aaeedae21eb77762dcb44ced134d0b9e241404f2c6c35a6c2e4a5b" + "digest": "sha256:9e3aafe76e94c6dba997e164ff0a9d51431f79b04ecd36d78ae41d7ef1333bfe" }, { "name": "neon-postgres-agent-platforms", "type": "skill-md", - "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", + "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", "url": "/docs/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", - "digest": "sha256:167e52b3c75f41b479a10a731ca2dd8729eec5f9f597d5a589a576a044345499" + "digest": "sha256:bba13ea7bf219fd7db71198785096bec92f43579b6def3281d077d3226228a5c" }, { "name": "neon-object-storage", diff --git a/public/docs/.well-known/skills/index.json b/public/docs/.well-known/skills/index.json index bffabb82d5f..f97091c222e 100644 --- a/public/docs/.well-known/skills/index.json +++ b/public/docs/.well-known/skills/index.json @@ -7,13 +7,6 @@ "SKILL.md" ] }, - { - "name": "claimable-postgres", - "description": "Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and SDK. Use when users ask for a quick Postgres environment, a throwaway DATABASE_URL for prototyping/tests, or \"just give me a DB now\". Triggers include: \"quick postgres\", \"temporary postgres\", \"no signup database\", \"no credit card database\", \"instant DATABASE_URL\", \"npx neon-new\", \"neon.new\", \"neon.new API\", \"claimable postgres API\".", - "files": [ - "SKILL.md" - ] - }, { "name": "neon-postgres-egress-optimizer", "description": "Diagnose and fix excessive Postgres egress (network data transfer) in a codebase. Use when a user mentions high database bills, unexpected data transfer costs, network transfer charges, egress spikes, \"why is my Neon bill so high\", \"database costs jumped\", SELECT * optimization, query overfetching, reduce Neon costs, optimize database usage, or wants to reduce data sent from their database to their application. Also use when reviewing query patterns for cost efficiency, even if the user doesn't explicitly mention egress or data transfer.", @@ -30,14 +23,14 @@ }, { "name": "neon", - "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\".", + "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\". Also use when there is no Neon account yet, the user cannot sign in or provide an API key right now and needs a project they can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup database, temporary postgres, quick postgres, a no credit card database, or npx neon-new.", "files": [ "SKILL.md" ] }, { "name": "neon-postgres-agent-platforms", - "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", + "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", "files": [ "SKILL.md" ] diff --git a/public/docs/ai/skills/claimable-postgres/SKILL.md b/public/docs/ai/skills/claimable-postgres/SKILL.md deleted file mode 100644 index 3e163678050..00000000000 --- a/public/docs/ai/skills/claimable-postgres/SKILL.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -name: claimable-postgres -description: >- - Provision instant temporary Postgres databases via Claimable Postgres by Neon - (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and - SDK. Use when users ask for a quick Postgres environment, a throwaway - DATABASE_URL for prototyping/tests, or "just give me a DB now". Triggers - include: "quick postgres", "temporary postgres", "no signup database", - "no credit card database", "instant DATABASE_URL", "npx neon-new", "neon.new", - "neon.new API", "claimable postgres API". -metadata: - parent: neon - source: https://github.com/neondatabase/agent-skills/tree/main/skills/claimable-postgres ---- - -**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more. - -If the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with: - -```bash -npx skills add neondatabase/agent-skills --skill neon -``` - -# Claimable Postgres - -Instant Postgres databases for local development, demos, prototyping, and test environments. No account required. Databases expire after 72 hours unless claimed to a Neon account. - -## Quick Start - -```bash -curl -s -X POST "https://neon.new/api/v1/database" \ - -H "Content-Type: application/json" \ - -d '{"ref": "agent-skills"}' -``` - -Parse `connection_string` and `claim_url` from the JSON response. Write `connection_string` to the project's `.env` as `DATABASE_URL`. - -For other methods (CLI, SDK, Vite plugin), see [Which Method?](#which-method) below. - -## Which Method? - -- **REST API**: Returns structured JSON. No runtime dependency beyond `curl`. Preferred when the agent needs predictable output and error handling. -- **CLI** (`npx neon-new@latest --yes`): Provisions and writes `.env` in one command. Convenient when Node.js is available and the user wants a simple setup. -- **SDK** (`neon-new/sdk`): Scripts or programmatic provisioning in Node.js. -- **Vite plugin** (`vite-plugin-neon-new`): Auto-provisions on `vite dev` if `DATABASE_URL` is missing. Use when the user has a Vite project. -- **Browser**: User cannot run CLI or API. Direct to https://neon.new. - -## Auto-provisioning - -If the agent needs a database to fulfill a task (e.g. "build me a todo app with a real database") and the user has not provided a connection string, provision one via the API and inform the user. Include the claim URL so they can keep it. - -## Agent Workflow - -### API path - -1. **Confirm intent:** If the request is ambiguous, confirm the user wants a temporary, no-signup database. Skip this if they explicitly asked for a quick or temporary database. -2. **Provision:** POST to `https://neon.new/api/v1/database` with `{"ref": "agent-skills"}`. -3. **Parse response:** Extract `connection_string`, `claim_url`, and `expires_at` from the JSON response. -4. **Write .env:** Write `DATABASE_URL=` to the project's `.env` (or the user's preferred file and key). Do not overwrite an existing key without confirmation. -5. **Seed (if needed):** If the user has a seed SQL file, run it against the new database: - ```bash - psql "$DATABASE_URL" -f seed.sql - ``` -6. **Report:** Cover every item in the [Output Checklist](#output-checklist). -7. **Optional:** Offer a quick connection test (e.g. `SELECT 1`). - -### CLI path - -1. **Check .env:** Check the target `.env` for an existing `DATABASE_URL` (or chosen key). If present, do not run. Offer remove, `--env`, or `--key` and get confirmation (see [Pre-run Check](#pre-run-check)). -2. **Confirm intent:** If the request is ambiguous, confirm the user wants a temporary, no-signup database. Skip this if they explicitly asked for a quick or temporary database. -3. **Gather options:** Use defaults unless context suggests otherwise (e.g., user mentions a custom env file, seed SQL, or logical replication). -4. **Run:** Execute with `@latest --yes` plus the confirmed options. Always use `@latest` to avoid stale cached versions. `--yes` skips interactive prompts that would stall the agent. - ```bash - npx neon-new@latest --yes --ref agent-skills --env .env.local --seed ./schema.sql - ``` -5. **Verify:** Confirm the connection string was written to the intended file. -6. **Report:** Cover every item in the [Output Checklist](#output-checklist). -7. **Optional:** Offer a quick connection test (e.g. `SELECT 1`). - -### Output Checklist - -Always report: - -- Where the connection string was written (e.g. `.env`) -- Which variable key was used (`DATABASE_URL` or custom key) -- The claim URL (from `.env` or API response) -- That unclaimed databases are temporary (72 hours): the database works now, and claiming within 72 hours keeps it permanently - -## Safety and UX Notes - -- Do not overwrite existing env vars. Check first, then use `--env` or `--key` (CLI) or skip writing (API) to avoid conflicts. -- Ask before running destructive seed SQL (`DROP`, `TRUNCATE`, mass `DELETE`). -- For production workloads, recommend standard Neon provisioning instead of temporary claimable databases. -- If users need long-term persistence, instruct them to open the claim URL right away. -- After writing credentials to an .env file, check that it's covered by .gitignore. If not, warn the user. Do not modify `.gitignore` without confirmation. - -## REST API - -**Base URL:** `https://neon.new/api/v1` - -### Create a database - -```bash -curl -s -X POST "https://neon.new/api/v1/database" \ - -H "Content-Type: application/json" \ - -d '{"ref": "agent-skills"}' -``` - -| Parameter | Required | Description | -| ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | -| `ref` | Yes | Tracking tag that identifies who provisioned the database. Use `"agent-skills"` when provisioning through this skill. | -| `enable_logical_replication` | No | Enable logical replication (default: false, cannot be disabled once enabled) | - -The `connection_string` returned by the API is a pooled connection URL. For a direct (non-pooled) connection (e.g. Prisma migrations), remove `-pooler` from the hostname. The CLI writes both pooled and direct URLs automatically. - -**Response:** - -```json -{ - "id": "019beb39-37fb-709d-87ac-7ad6198b89f7", - "status": "UNCLAIMED", - "neon_project_id": "gentle-scene-06438508", - "connection_string": "postgresql://...", - "claim_url": "https://neon.new/claim/019beb39-...", - "expires_at": "2026-01-26T14:19:14.580Z", - "created_at": "2026-01-23T14:19:14.580Z", - "updated_at": "2026-01-23T14:19:14.580Z" -} -``` - -### Check status - -```bash -curl -s "https://neon.new/api/v1/database/{id}" -``` - -Returns the same response shape. Status transitions: `UNCLAIMED` -> `CLAIMING` -> `CLAIMED`. After the database is claimed, `connection_string` returns `null`. - -### Error responses - -| Condition | HTTP | Message | -| ---------------------- | ---- | -------------------------------- | -| Missing or empty `ref` | 400 | `Missing referrer` | -| Invalid database ID | 400 | `Database not found` | -| Invalid JSON body | 500 | `Failed to create the database.` | - -## CLI - -```bash -npx neon-new@latest --yes -``` - -Provisions a database and writes the connection string to `.env` in one step. Always use `@latest` and `--yes` (skips interactive prompts that would stall the agent). - -### Pre-run Check - -Check if `DATABASE_URL` (or the chosen key) already exists in the target `.env`. The CLI exits without provisioning if it finds the key. - -If the key exists, offer the user three options: - -1. Remove or comment out the existing line, then rerun. -2. Use `--env` to write to a different file (e.g. `--env .env.local`). -3. Use `--key` to write under a different variable name. - -Get confirmation before proceeding. - -### Options - -| Option | Alias | Description | Default | -| ----------------------- | ----- | --------------------------------------------------------------------- | -------------- | -| `--yes` | `-y` | Skip prompts, use defaults | `false` | -| `--env` | `-e` | .env file path | `./.env` | -| `--key` | `-k` | Connection string env var key | `DATABASE_URL` | -| `--prefix` | `-p` | Prefix for generated public env vars | `PUBLIC_` | -| `--seed` | `-s` | Path to seed SQL file | none | -| `--logical-replication` | `-L` | Enable logical replication | `false` | -| `--ref` | `-r` | Referrer id (use `agent-skills` when provisioning through this skill) | none | - -Alternative package managers: `yarn dlx neon-new@latest`, `pnpm dlx neon-new@latest`, `bunx neon-new@latest`, `deno run -A neon-new@latest`. - -### Output - -The CLI writes to the target `.env`: - -``` -DATABASE_URL=postgresql://... # pooled (use for application queries) -DATABASE_URL_DIRECT=postgresql://... # direct (use for migrations, e.g. Prisma) -PUBLIC_POSTGRES_CLAIM_URL=https://neon.new/claim/... -``` - -## SDK - -Use for scripts and programmatic provisioning flows. - -```typescript -import { instantPostgres } from "neon-new"; - -const { databaseUrl, databaseUrlDirect, claimUrl, claimExpiresAt } = - await instantPostgres({ - referrer: "agent-skills", - seed: { type: "sql-script", path: "./init.sql" }, - }); -``` - -Returns `databaseUrl` (pooled), `databaseUrlDirect` (direct, for migrations), `claimUrl`, and `claimExpiresAt` (Date object). The `referrer` parameter is required. - -## Vite Plugin - -For Vite projects, `vite-plugin-neon-new` auto-provisions a database on `vite dev` if `DATABASE_URL` is missing. Install with `npm install -D vite-plugin-neon-new`. See the [Claimable Postgres docs](https://neon.com/docs/reference/claimable-postgres#vite-plugin) for configuration. - -## Claiming - -Claiming is optional. The database works immediately without it. To optionally claim, the user opens the claim URL in a browser, where they sign in or create a Neon account to claim the database. - -- **API/SDK:** Give the user the `claim_url` from the create response. -- **CLI:** `npx neon-new@latest claim` reads the claim URL from `.env` and opens the browser automatically. - -Users cannot claim into Vercel-linked orgs; they must choose another Neon org. - -## Neon Infrastructure as Code (`neon.ts`) - -Claimable databases are deliberately throwaway and provisioned through `neon.new` (above), so they aren't managed by `neon.ts`. Once a user **claims** a database into a Neon account it becomes a normal Neon project — at which point `neon.ts`, Neon's infrastructure-as-code file, is how you manage it going forward (see the `neon` skill for the full reference): declare the services its branches should have, program per-branch compute, and get type-safe env vars. - -```bash -npm i @neon/config -``` - -```typescript -// neon.ts -import { defineConfig } from "@neon/config/v1"; - -export default defineConfig({ - auth: true, // Neon Auth, once you outgrow a bare connection string - dataApi: true, // Data API - branch: (branch) => (branch.exists ? {} : { ttl: "7d" }), // ephemeral non-default branches -}); -``` - -```bash -neon config apply # provision the declared services (neon deploy is an alias) -``` - -If a project needs branching, multiple services, or durable infrastructure tracked in version control, recommend claiming first and then adopting `neon.ts` — rather than re-provisioning throwaway claimable databases. - -## Defaults and Limits - -| Parameter | Value | -| --------- | --------- | -| Provider | AWS | -| Region | us-east-2 | -| Postgres | 17 | - -Region cannot be changed for claimable databases. Unclaimed databases have stricter quotas. Claiming resets limits to free plan defaults. - -| | Unclaimed | Claimed (Free plan) | -| ---------- | --------- | ------------------- | -| Storage | 100 MB | 512 MB | -| Transfer | 1 GB | ~5 GB | -| Branches | No | Yes | -| Expiration | 72 hours | None | diff --git a/public/docs/ai/skills/neon-postgres-agent-platforms/SKILL.md b/public/docs/ai/skills/neon-postgres-agent-platforms/SKILL.md index 8696311c5c3..75491dc1c6e 100644 --- a/public/docs/ai/skills/neon-postgres-agent-platforms/SKILL.md +++ b/public/docs/ai/skills/neon-postgres-agent-platforms/SKILL.md @@ -6,7 +6,8 @@ description: >- whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects - between orgs, choosing personal vs organization vs project-scoped API keys, + between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs + organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon @@ -19,11 +20,12 @@ license: Apache-2.0 Companion to `**neon-postgres**` (install that first). This skill covers fleet-scale control plane for the Neon Agent Program: dual-org layout, project -transfer, per-tenant provisioning, compound checkpoints, consumption, and -commercial terms. +transfer, per-tenant provisioning, compound checkpoints, consumption, commercial +terms, and when to give agents Management API access via `@neon/tools`. For connection strings, drivers, ORMs, branching tutorials, Auth in apps, Data -API, and MCP, use `**neon-postgres**` and [Neon docs](https://neon.com/docs). +API, and Neon's hosted MCP, use `**neon-postgres**` and +[Neon docs](https://neon.com/docs). ## Scope @@ -31,6 +33,7 @@ Use `**neon-postgres**` for general Neon usage. Use **this skill** when the question involves: - Dual-org economics and API keys (personal, organization, project-scoped) +- `@neon/sdk` for the control plane vs `@neon/tools` for agent-facing Management API access - Project-per-tenant provisioning and transfer - Fleet-wide snapshot/restore orchestration and housekeeping - Compound checkpoints @@ -58,6 +61,84 @@ keeps markdown guides beside the runnable examples; is the script catalog and env map. The human **Quick start** is the root [README](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/README.md#quick-start). +## SDK vs agent tools + +Your control plane should call +[`@neon/sdk`](https://www.npmjs.com/package/@neon/sdk). The sample scripts in +this repo do. + +The [Neon MCP server](https://github.com/neondatabase/mcp-server-neon) is a +custom agent-facing layer: MCP tool handlers written over `@neon/sdk`. + +Use [`@neon/tools`](https://www.npmjs.com/package/@neon/tools) when you want to +give agents on your platform direct Neon management access without writing those +handlers. It publishes generated wrappers for a selected set of SDK methods as +agent tools, with adapters for MCP, Eve, and Mastra. + +These public client methods are not tools: `projects.create`, `branches.create`, +`operations.waitFor`, `postgres.roles.password`, and `storage.objects.get`. Use +`projects.createAndConnect` and `branches.createWithCompute` for creates that +attach compute and return a connection string. Waiting is what the write tools +already do. Generated schemas are strict: a newly added API field is rejected +until you upgrade `@neon/tools`, or call `@neon/sdk` directly. + +Selectors are SDK paths (`projects.list`). Call `publishedId` for the +model-facing id (`projects.list` → `list_projects`). `toolIds` lists every +selector. MCP 2.x uses `@neon/tools/mcp`; MCP 1.x uses `@neon/tools/mcp-v1`. + +```ts +import { McpServer } from "@modelcontextprotocol/server"; +import { createNeonTools } from "@neon/tools"; +import { registerNeonTools } from "@neon/tools/mcp"; + +const apiKey = process.env.NEON_API_KEY; +if (!apiKey) throw new Error("NEON_API_KEY is required"); + +const tools = createNeonTools({ + apiKey, + tools: [ + "projects.list", + "projects.createAndConnect", + "branches.createWithCompute", + ] as const, +}); + +const server = new McpServer({ name: "neon", version: "1.0.0" }); +registerNeonTools(server, tools); +``` + +`apiKey` accepts a function so a short-lived token can be refreshed per +request. A remote MCP server that already authenticated the client can omit +`apiKey` at construction; `registerNeonTools` then sends `authInfo.token`. + +MCP annotations are advisory. Hosts using `@neon/tools/mcp` must read +`neon/requiresApproval` in MCP `_meta` and enforce their own approval policy +before execution. The Eve and Mastra adapters map that flag to Eve's +`approval` hook and Mastra's `requireApproval`. Every non-read operation is +marked as requiring approval, as are reads that return connection credentials. + +Select only the methods each agent needs. For a tenant-scoped agent, inject the +path `project_id` so the model cannot pick another project on tools that take +that path parameter: + +```ts +const tools = createNeonTools({ + apiKey, + tools: ["projects.get", "branches.createWithCompute"] as const, + inject: { + projectId: tenantProjectId, + omitFromSchema: true, + }, +}); +``` + +`inject.projectId` fills URL path `project_id` only. It does not hide query or +body fields with that name, and it does not constrain tools that have no project +path (for example `projects.list`). Pair it with a **project-scoped API key** +when the agent must not see the rest of the org. + +Full API: [`@neon/tools` README](https://github.com/neondatabase/neon-pkgs/tree/main/packages/tools#readme). + ## Gotchas Non-obvious facts agents often get wrong: @@ -332,8 +413,9 @@ Runnable Management API automation from - **Doc index:** [SCRIPT-OVERVIEW.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/SCRIPT-OVERVIEW.md) -All scripts use `@neon/sdk` only. Shared +These scripts use `@neon/sdk` only. Shared [utils.ts](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/scripts/utils.ts) builds the client and resolves the default branch; the SDK polls async -operations (readiness) for you. For SQL access from app code (drivers, pooling, ORMs), -use `**neon-postgres`**. \ No newline at end of file +operations (readiness) for you. For agent-facing Management API tools, see +**SDK vs agent tools** above. For SQL access from app code (drivers, pooling, +ORMs), use `**neon-postgres`**. diff --git a/public/docs/ai/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md b/public/docs/ai/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md index 5c2280baf55..896a8713e28 100644 --- a/public/docs/ai/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md +++ b/public/docs/ai/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md @@ -1,8 +1,8 @@ # Management API samples (`scripts/`) -Small **Node.js + TypeScript** scripts that call Neon’s official **[Management API TypeScript SDK](https://neon.com/docs/reference/typescript-sdk.md)** ([`@neon/sdk`](https://registry.npmjs.org/@neon/sdk)) via **`createNeonClient`**, **no other Neon npm packages**. Sources live in **[`scripts/`](../scripts/)**; **`npm run build`** runs **`tsc`** and emits **`dist/scripts/*.js`** per **[`tsconfig.json`](../scripts/tsconfig.json)**. **`npm run typecheck`** runs **`tsc --noEmit`** (no emit). Scripts **`import "dotenv/config"`** so variables from **`.env`** load automatically; run with **`node dist/scripts/.js`** or **`npm run …`** (each npm script runs **`build`** then **`node dist/scripts/...`**). +Small **Node.js + TypeScript** scripts that call Neon’s official **[Management API TypeScript SDK](https://neon.com/docs/reference/typescript-sdk.md)** ([`@neon/sdk`](https://registry.npmjs.org/@neon/sdk)) via **`createNeonClient`**. These scripts use **no other Neon npm packages**. Sources live in **[`scripts/`](../scripts/)**; **`npm run build`** runs **`tsc`** and emits **`dist/scripts/*.js`** per **[`tsconfig.json`](../scripts/tsconfig.json)**. **`npm run typecheck`** runs **`tsc --noEmit`** (no emit). Scripts **`import "dotenv/config"`** so variables from **`.env`** load automatically; run with **`node dist/scripts/.js`** or **`npm run …`** (each npm script runs **`build`** then **`node dist/scripts/...`**). -**When we say “Neon TypeScript SDK” here, we mean [`@neon/sdk`](https://registry.npmjs.org/@neon/sdk) and nothing else**, not `@neondatabase/serverless`, `@neondatabase/neon-js`, `@neondatabase/toolkit`, or any other Neon package. +**When we say “Neon TypeScript SDK” in this samples catalog, we mean [`@neon/sdk`](https://registry.npmjs.org/@neon/sdk) and nothing else**, not `@neondatabase/serverless`, `@neondatabase/neon-js`, `@neondatabase/toolkit`, or any other Neon package. To give agents Management API access without writing tool handlers, use [`@neon/tools`](https://www.npmjs.com/package/@neon/tools) as described in [SDK vs agent tools](../SKILL.md#sdk-vs-agent-tools). Use these to prototype **per-tenant provisioning**, **fleet branching/snapshot orchestration**, **database versioning** (snapshots + restore), **org transfer** (free ↔ paid org), **consumption** polling, and **Neon Auth management** endpoints, not introductory app connectivity (that is **`neon-postgres`** + app docs). @@ -225,7 +225,7 @@ node --env-file=.env dist/scripts/auth-users.js meta ## Shared helpers -[`scripts/utils.ts`](../scripts/utils.ts) holds **shared helpers** on top of the same **`@neon/sdk`** surface: a configured client factory (`neonClient` — `throwOnError` + `waitForReadiness`) and default-branch resolution (`getProductionBranchId`). The SDK itself handles **readiness polling**, retries, and typed errors, so the scripts no longer hand-roll an operation poller. There is no second Neon client package. +[`scripts/utils.ts`](../scripts/utils.ts) holds **shared helpers** on top of the same **`@neon/sdk`** surface: a configured client factory (`neonClient` — `throwOnError` + `waitForReadiness`) and default-branch resolution (`getProductionBranchId`). The SDK itself handles **readiness polling**, retries, and typed errors, so the scripts no longer hand-roll an operation poller. For agent-facing Management API tools, see [SDK vs agent tools](../SKILL.md#sdk-vs-agent-tools). --- diff --git a/public/docs/ai/skills/neon/SKILL.md b/public/docs/ai/skills/neon/SKILL.md index 013cb8bc8a2..afa8dc367bf 100644 --- a/public/docs/ai/skills/neon/SKILL.md +++ b/public/docs/ai/skills/neon/SKILL.md @@ -9,7 +9,12 @@ description: >- are the trigger: "object storage" or "S3", "buckets", "serverless functions", "AI gateway", "call an LLM", "logs", "branch logs", "query logs", "log export", "Loki", "Grafana", "observability", "telemetry", "postgres", - "database", or "backend". + "database", or "backend". Also use when there is no Neon account yet, the + user cannot sign in or provide an API key right now and needs a project they + can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, + Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup + database, temporary postgres, quick postgres, a no credit card database, or + npx neon-new. metadata: source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon --- @@ -79,15 +84,14 @@ Neon provides a set of agent skills in addition to the official documentation. W The skills below live in the [`neondatabase/agent-skills`](https://github.com/neondatabase/agent-skills) repo: -| Skill | Use it for | -| --- | --- | -| `neon-postgres` | Working with databases, including connections, schemas, queries, and autoscaling: SQL development, schema design, performance optimization, and scaling decisions. | -| `neon-postgres-branches` | Choosing or creating the right branch type for dev, preview, test, or CI workflows. Use this skill as a slash command. | -| `neon-object-storage` | Storing and serving files (uploads, images, blobs), including branching them with the database. | -| `neon-functions` | Deploying long-running or streaming serverless functions — APIs, agents, SSE/WebSocket servers. | -| `neon-ai-gateway` | Calling an LLM or routing across model providers with one credential, including discovering the branch's servable models at runtime via the OpenAI-compatible `/v1/models` endpoint. | -| `claimable-postgres` | Provisioning instant, claimable temporary Postgres databases (for example, one per end user or demo). | -| `neon-postgres-egress-optimizer` | Diagnosing or fixing excessive Postgres egress (network data-transfer) costs in a codebase. | +| Skill | Use it for | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `neon-postgres` | Working with databases, including connections, schemas, queries, and autoscaling: SQL development, schema design, performance optimization, and scaling decisions. | +| `neon-postgres-branches` | Choosing or creating the right branch type for dev, preview, test, or CI workflows. Use this skill as a slash command. | +| `neon-object-storage` | Storing and serving files (uploads, images, blobs), including branching them with the database. | +| `neon-functions` | Deploying long-running or streaming serverless functions — APIs, agents, SSE/WebSocket servers. | +| `neon-ai-gateway` | Calling an LLM or routing across model providers with one credential, including discovering the branch's servable models at runtime via the OpenAI-compatible `/v1/models` endpoint. | +| `neon-postgres-egress-optimizer` | Diagnosing or fixing excessive Postgres egress (network data-transfer) costs in a codebase. | For guidance on agent platforms that provision and operate Lakebase Postgres on Neon at scale, use `neon-postgres-agent-platforms`, which lives in a separate repo: [`neondatabase/neon-for-agent-platforms`](https://github.com/neondatabase/neon-for-agent-platforms). @@ -121,6 +125,15 @@ Use the same method that was used to install them. With the `skills` CLI, run th ## Getting Started with Neon +Before `npx neon@latest init --agent`, check whether the CLI is already authenticated: + +- `NEON_API_KEY` is set +- `npx neon@latest profile list -o json` lists a profile whose `account` is not `-` + +A `DEFAULT` row with `account: "-"` and `file: "missing"` is not an account. If `neon` is not installed, or `npx neon@latest profile list` cannot run, that is not an account. + +If none of those hold, follow [Starting without a Neon account](#starting-without-a-neon-account). + The easiest way to get started with Neon is to use our CLI and the project bootstrap wizard: ```bash @@ -168,6 +181,16 @@ Useful MCP tools to initialize a project: - `create_project` — Creates a new Neon project in your Neon account. A project acts as a container for branches, databases, roles, and computes. - `get_connection_string` — Returns your database connection string. +## Starting without a Neon account + +If the Getting Started account check found credentials, use them. If a command waits on a browser (`Awaiting authentication in web browser`) or authentication fails, stop and ask the user to sign in (`neon auth`) or mint an API key. Prefer that over Claimable Neon unless they say otherwise. + +If they cannot sign in or provide a key right now, ask before using Claimable Neon. Continue only after they say yes. That is a temporary workaround. + +If there is no Neon account yet, follow [references/claimable-neon.md](https://neon.com/docs/ai/skills/neon/references/claimable-neon.md). Do not run `neon init --agent` or `neon auth` on this path; those need a human Neon account. If `neon claim` is missing, the reference has the REST fallback. + +Requests for neon.new, Claimable Postgres, claimable.neon.tech, instant Postgres, or a no-signup database are the same path. + ## Neon Infrastructure as Code `neon.ts` is Neon's branch config and infrastructure-as-code file: declare which Neon services your project's branches should have, get type-safe env vars, and program branch settings — all in TypeScript. It's the config layer for your Neon services, and it composes with the branch-first loop below. Add it with `@neon/config`: @@ -208,12 +231,8 @@ export default defineConfig({ auth: true, dataApi: true, preview: { - functions: { - /* ... */ - }, // see the neon-functions skill - buckets: { - /* ... */ - }, // see the neon-object-storage skill + functions: {}, + buckets: {}, aiGateway: true, // see the neon-ai-gateway skill }, }); @@ -395,7 +414,11 @@ for await (const record of neon.logs.query(projectId, branchId, { } const { data: fields } = await neon.logs.fields(projectId, branchId); -const { data: serviceNames } = await neon.logs.fieldValues(projectId, branchId, "service_name"); +const { data: serviceNames } = await neon.logs.fieldValues( + projectId, + branchId, + "service_name", +); ``` `query`'s iterator always throws on error, but `fields` and `fieldValues` follow the client's `throwOnError`, which defaults to `false` and hands back `{ data, error }`. `fieldValues` resolves to the whole response, not a bare array: read `serviceNames.values`, and treat them as an arbitrary subset whenever `serviceNames.is_truncated` is true. diff --git a/public/docs/ai/skills/neon/references/claimable-neon.md b/public/docs/ai/skills/neon/references/claimable-neon.md new file mode 100644 index 00000000000..e67c63c7f1f --- /dev/null +++ b/public/docs/ai/skills/neon/references/claimable-neon.md @@ -0,0 +1,91 @@ +# Claimable Neon + +Claimable Neon provisions a temporary Neon project — Lakebase Postgres, and optionally the Data API and Managed Better Auth — before a human creates an account. The agent holds an identity assertion, not a Neon API key. A human can later claim the project into their organization. + +This flow follows the [auth.md](https://claimable.neon.tech/auth.md) protocol. Fetch `https://claimable.neon.tech/auth.md` for request and response fields. REST is on `https://claimable.neon.tech`. Use the table below; do not invent other identity paths. + +Use this after the neon skill account check found no account. + +## Path + +1. Install the CLI: `npm i -g neon@latest` +2. If `neon claim --help` does not list `create`, skip to [If neon claim is missing](#if-neon-claim-is-missing). +3. Write a `neon.ts` that declares the services you need, or skip the file and pass `--service` on create. Postgres is always requested. +4. Create the project: `neon claim create --env-pull` (add `--service data-api --service auth` if there is no `neon.ts`) +5. If create did not write env, pull it: `neon env pull` +6. Use the `neon-postgres` skill for connections, schemas, and queries. Install it if it is missing: `neon skills -s neon-postgres` + +Do not run `neon init --agent` or `neon auth` on this path; those need a human Neon account. `--api-key` and `--profile` are refused on `neon claim`. + +```bash +npm i -g neon@latest +neon claim --help +``` + +If that help lists `create` and you need Auth or the Data API, `npm i @neon/config` and write `neon.ts`. Then `neon claim create --env-pull`. + +```typescript +import { defineConfig } from "@neon/config/v1"; + +export default defineConfig({ + auth: true, + dataApi: true, +}); +``` + +`neon claim create` reads `neon.ts` when it is present. It writes provisioned vars to an existing `.env`, otherwise `.env.local`, and gitignores that file. If `.env` or `.env.local` already has a `DATABASE_URL` (or other Neon-managed keys), pass `--file ` or `--no-env-pull`. The identity assertion is the pre-claim credential. + +Before claim, Postgres is always granted; Auth and the Data API are granted when requested. Functions, Object Storage, and AI Gateway come back with `granted: false` and `reason: "requires_claim"`. The CLI prints those as `denied_capabilities`. Report what you were given. Do not retry or strip them. + +After create, report the `project_id`, `project_expires_at`, and any denied capabilities. Do not invent the window. + +## Claim + +Do not mint a claim URL until the human is ready. Opening the URL does not freeze access. Continuing to Neon starts the transfer and rotates `DATABASE_URL`. Existing access tokens are revoked. Auth and the Data API stay enabled when they were granted. + +When `reconciled` is true, the pre-claim `DATABASE_URL` no longer works. Auth and Data API URLs stay. The human signs in with `neon auth`. Then the agent runs `neon link --agent` and `neon env pull` to write the new `DATABASE_URL`. `neon link --agent` discovers the project after that sign-in. + +### With the CLI + +When the human is ready, run `neon claim accept --no-open`. Bare `neon claim accept` opens a browser. Report the `verification_url`, `user_code`, and `expires_in_seconds` the CLI printed (HTTP names: `verification_uri_complete`, `user_code`, `expires_in`). If the code expires, run `neon claim accept --no-open` again. Poll with `neon claim status`. The CLI re-exchanges the assertion; do not call the token endpoint yourself. + +```bash +neon claim accept --no-open +neon claim status +``` + +Permanently delete the unclaimed project (this does not cancel a claim): + +```bash +neon claim delete --yes +``` + +### With REST + +An agent must not complete the claim. Do not `POST /v1/projects/{id}/claim` until the human is ready. The human opens `verification_uri_complete` and accepts the transfer. If the claim code expires, `POST /v1/projects/{id}/claim` again. The live claim response also includes `user_code` and `expires_in`. `auth.md` documents `verification_uri_complete` and the polling `interval`. + +After the human continues to Neon, existing access tokens are revoked: re-exchange the identity assertion, then poll `GET /v1/projects/{id}/claim` with that token at the interval `auth.md` returns. `claim_in_progress` means keep polling with the post-redemption token, not the token from create. Report `verification_uri_complete`, `user_code`, and `expires_in`. + +When `error.code` is `capability_requires_claim`, preserve the denied capability and give the human a claim link instead of retrying or silently omitting it. + +Only `invalid_grant`, `project_expired`, and `project_claimed` mean the stored identity assertion is dead. `token_expired` means re-exchange the assertion. + +## If neon claim is missing + +Fall back to the REST API. Fetch `https://claimable.neon.tech/auth.md` for request and response fields. The claimable resource is `/v1/projects/{id}` on `https://claimable.neon.tech`, not `/v1/databases/{id}`. Follow [Claim](#claim) for when to mint, what rotates, and what to do after `reconciled`. + +```http +POST https://claimable.neon.tech/v1/agent/identity +POST https://claimable.neon.tech/v1/oauth2/token +GET https://claimable.neon.tech/v1/projects/{id}/credentials +POST https://claimable.neon.tech/v1/projects/{id}/claim +GET https://claimable.neon.tech/v1/projects/{id}/claim +DELETE https://claimable.neon.tech/v1/projects/{id} +``` + +| CLI | REST | +| ----------------------------- | ------------------------------------------------------------------------------------------------- | +| `neon claim create` | `POST /v1/agent/identity`, then `POST /v1/oauth2/token`, then `GET /v1/projects/{id}/credentials` | +| `neon claim accept --no-open` | `POST /v1/projects/{id}/claim` | +| `neon claim status` | `GET /v1/projects/{id}/claim` | +| `neon claim delete --yes` | `DELETE /v1/projects/{id}` | diff --git a/public/pricing.md b/public/pricing.md index 4a221cf5314..ae58e9842b3 100644 --- a/public/pricing.md +++ b/public/pricing.md @@ -73,7 +73,7 @@ See [Plans](https://neon.com/docs/introduction/plans.md) for full details. ### How can I try Neon without signing up? -Use [Claimable Postgres](https://neon.new/) for an instant database, with no signup and no card. Run `npx neon-new --yes` (or the [API](https://neon.com/docs/reference/claimable-postgres.md)) to provision Postgres that lasts 72 hours. Claim it to a Neon account before expiration to keep it. +Use [Claimable Neon](https://neon.com/claimable-neon) for an instant project, with no signup and no card. Provision from that page or the [API](https://neon.com/docs/reference/claimable-neon.md). Claim it to a Neon account before expiration to keep it. ### What is a project? diff --git a/scripts/docs-checks/neonctl/overrides.json b/scripts/docs-checks/neonctl/overrides.json index 707844781b4..d0b48e5367a 100644 --- a/scripts/docs-checks/neonctl/overrides.json +++ b/scripts/docs-checks/neonctl/overrides.json @@ -193,6 +193,18 @@ } } } + }, + "claim": { + "commands": { + "create": { + "options": { + "service": { + "type": "array", + "describe": "Services to request for the claimable project: postgres, auth, data-api, functions, object-storage, ai-gateway. Repeat the flag or comma-separate. Postgres is always included. Services unavailable before claim are recorded and reported." + } + } + } + } } } } diff --git a/scripts/docs-checks/neonctl/schema.json b/scripts/docs-checks/neonctl/schema.json index 6371a9eadee..d3b397c6a03 100644 --- a/scripts/docs-checks/neonctl/schema.json +++ b/scripts/docs-checks/neonctl/schema.json @@ -893,6 +893,95 @@ } ] }, + "claim": { + "aliases": [ + "claimable" + ], + "positionals": [], + "options": { + "claimable-host": { + "type": "string", + "describe": "Claimable Neon service origin", + "defaultText": "process.env.CLAIMABLE_NEON_HOST ?? DEFAULT_CLAIMABLE_ORIGIN", + "hidden": true + } + }, + "commands": { + "accept": { + "name": "accept", + "aliases": [], + "positionals": [], + "options": { + "open": { + "type": "boolean", + "describe": "Open the verification URL in a browser", + "default": true + } + }, + "commands": {}, + "describe": "Create a claim code and open the URL where a human signs in and takes the project" + }, + "create": { + "name": "create", + "aliases": [], + "positionals": [], + "options": { + "config": { + "type": "string", + "describe": "Path to neon.ts. Defaults to walking up from the current directory" + }, + "env-pull": { + "type": "boolean", + "describe": "Write the provisioned DATABASE_URL and service URLs to a dotenv file", + "default": true + }, + "file": { + "type": "string", + "describe": "Target dotenv file. Defaults to an existing .env, otherwise .env.local" + }, + "service": { + "type": "array", + "describe": "Services to request for the claimable project: postgres, auth, data-api, functions, object-storage, ai-gateway. Repeat the flag or comma-separate. Postgres is always included. Services unavailable before claim are recorded and reported." + } + }, + "commands": {}, + "describe": "Create a temporary Neon project without an account" + }, + "delete": { + "name": "delete", + "aliases": [], + "positionals": [], + "options": { + "yes": { + "type": "boolean", + "describe": "Skip the confirmation prompt", + "default": false, + "alias": "y" + } + }, + "commands": {}, + "describe": "Permanently delete the linked unclaimed project" + }, + "list": { + "name": "list", + "aliases": [], + "positionals": [], + "options": {}, + "commands": {}, + "describe": "List claimable projects saved on this machine" + }, + "status": { + "name": "status", + "aliases": [], + "positionals": [], + "options": {}, + "commands": {}, + "describe": "Show the linked claimable project's lifecycle and claim status" + } + }, + "describe": "Create and claim temporary Neon projects", + "usage": "$0 claim [options]" + }, "config": { "aliases": [], "positionals": [], diff --git a/scripts/verify-agent-endpoints.mjs b/scripts/verify-agent-endpoints.mjs index d6bea5930f0..4b60be4c74b 100644 --- a/scripts/verify-agent-endpoints.mjs +++ b/scripts/verify-agent-endpoints.mjs @@ -224,6 +224,37 @@ const SCHEMAS = { info: { type: 'object', required: ['title'], properties: { title: { type: 'string' } } }, }, }, + claimableAuthorizationServer: { + type: 'object', + required: [ + 'issuer', + 'token_endpoint', + 'jwks_uri', + 'grant_types_supported', + 'token_endpoint_auth_methods_supported', + 'response_types_supported', + 'agent_auth', + ], + properties: { + issuer: { type: 'string' }, + token_endpoint: { type: 'string' }, + revocation_endpoint: { type: 'string' }, + jwks_uri: { type: 'string' }, + grant_types_supported: { type: 'array', items: { type: 'string' } }, + token_endpoint_auth_methods_supported: { type: 'array', items: { type: 'string' } }, + response_types_supported: { type: 'array', items: { type: 'string' } }, + agent_auth: { + type: 'object', + required: ['skill', 'identity_endpoint', 'claim_endpoint'], + properties: { + skill: { type: 'string' }, + identity_endpoint: { type: 'string' }, + claim_endpoint: { type: 'string' }, + identity_types_supported: { type: 'array', items: { type: 'string' } }, + }, + }, + }, + }, }; const VALIDATORS = { @@ -353,10 +384,7 @@ const VALIDATORS = { if (res.status === 0) { const debt = output.includes('[SYNC DEBT]'); checks.push( - ok( - 'models.dev mirror', - debt ? 'behind — upstream PR owed' : output.split('\n').pop() - ) + ok('models.dev mirror', debt ? 'behind — upstream PR owed' : output.split('\n').pop()) ); } else if (res.status === 1) { checks.push(fail('models.dev mirror', `advertises a model we do not publish — ${output}`)); @@ -440,6 +468,67 @@ const VALIDATORS = { if (!liveJson) return [fail(`schema (${entry.spec.name})`, 'response was not valid JSON')]; return [schemaCheck(entry.spec.name, SCHEMAS.openapi, liveJson)]; }, + + 'claimable-authorization-server'(payload, entry, sot) { + const checks = [schemaCheck(entry.spec.name, SCHEMAS.claimableAuthorizationServer, payload)]; + checks.push(equalsCheck('issuer matches SoT', payload.issuer, sot.CLAIMABLE.issuer)); + checks.push( + equalsCheck('token_endpoint matches SoT', payload.token_endpoint, sot.CLAIMABLE.tokenEndpoint) + ); + checks.push( + equalsCheck('jwks_uri matches SoT', payload.jwks_uri, sot.CLAIMABLE.jwksUri) + ); + checks.push( + Array.isArray(payload.token_endpoint_auth_methods_supported) && + payload.token_endpoint_auth_methods_supported.includes('none') + ? ok('token endpoint advertises no client authentication') + : fail( + 'token endpoint advertises no client authentication', + payload.token_endpoint_auth_methods_supported + ) + ); + checks.push( + equalsCheck('agent_auth.skill matches SoT', payload.agent_auth?.skill, sot.CLAIMABLE.skillUrl) + ); + checks.push( + equalsCheck( + 'identity_endpoint matches SoT', + payload.agent_auth?.identity_endpoint, + sot.CLAIMABLE.identityEndpoint + ) + ); + const skill = new URL(sot.CLAIMABLE.skillUrl); + const issuer = new URL(sot.CLAIMABLE.issuer); + checks.push( + skill.origin === issuer.origin + ? ok('skill is on the issuer host') + : fail('skill is on the issuer host', `${skill.origin} vs ${issuer.origin}`) + ); + checks.push( + issuer.pathname.replace(/\/+$/, '') !== '' + ? ok('issuer is a path identifier') + : fail('issuer is a path identifier', issuer.href) + ); + try { + const markdown = fs.readFileSync(path.join(ROOT, sot.CLAIMABLE.authMarkdownPath), 'utf-8'); + for (const [name, value] of [ + ['skill URL', sot.CLAIMABLE.skillUrl], + ['token endpoint', sot.CLAIMABLE.tokenEndpoint], + ['identity endpoint', sot.CLAIMABLE.identityEndpoint], + ['resource', sot.CLAIMABLE.resource], + ['issuer', sot.CLAIMABLE.issuer], + ]) { + checks.push( + markdown.includes(value) + ? ok(`auth.md contains ${name}`) + : fail(`auth.md contains ${name}`, `missing ${value}`) + ); + } + } catch (err) { + checks.push(fail('auth.md readable', err.message)); + } + return checks; + }, }; // ── run one entry ───────────────────────────────────────────────────────────── diff --git a/src/app/.well-known/ai-catalog.json/catalog.json b/src/app/.well-known/ai-catalog.json/catalog.json index 8e7a40d8141..5cad68f28fe 100644 --- a/src/app/.well-known/ai-catalog.json/catalog.json +++ b/src/app/.well-known/ai-catalog.json/catalog.json @@ -25,12 +25,6 @@ "url": "https://neon.com/.well-known/agent-skills/neon-postgres/SKILL.md", "description": "Guides and best practices for working with Lakebase Postgres, the database behind Neon. Covers setup, connection methods and drivers, pooled vs direct connections, branching, schema migrations, autoscaling, scale-to-zero, instant restore, read replicas, connection pooling, IP allow lists, and logical replication. Use when users ask about \"Lakebase Postgres\", \"Neon setup\", \"connect to Neon\", \"Neon project\", \"DATABASE_URL\", \"serverless Postgres\", \"Neon CLI\", \"neon\", \"Neon MCP\", \"Neon Auth\", \"@neondatabase/serverless\", \"@neondatabase/neon-js\", \"scale to zero\", \"Neon autoscaling\", \"Neon read replica\", \"Neon connection pooling\", or \"schema migrations\"." }, - { - "identifier": "urn:air:neon.com:skill:claimable-postgres", - "type": "application/agent-skills+md", - "url": "https://neon.com/.well-known/agent-skills/claimable-postgres/SKILL.md", - "description": "Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new) with no login, signup, or credit card. Supports REST API, CLI, and SDK. Use when users ask for a quick Postgres environment, a throwaway DATABASE_URL for prototyping/tests, or \"just give me a DB now\". Triggers include: \"quick postgres\", \"temporary postgres\", \"no signup database\", \"no credit card database\", \"instant DATABASE_URL\", \"npx neon-new\", \"neon.new\", \"neon.new API\", \"claimable postgres API\"." - }, { "identifier": "urn:air:neon.com:skill:neon-postgres-egress-optimizer", "type": "application/agent-skills+md", @@ -47,13 +41,13 @@ "identifier": "urn:air:neon.com:skill:neon", "type": "application/agent-skills+md", "url": "https://neon.com/.well-known/agent-skills/neon/SKILL.md", - "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\"." + "description": "Overview of Neon, a complete set of cloud backend primitives for apps and agents, spanning Lakebase Postgres, Auth, the Data API, Object Storage, Compute Functions, and the AI Gateway. Start here to route to the right Neon skill, set up the CLI or MCP server, and follow the branch-first workflow. Use when \"Neon\" or \"Lakebase Postgres\" is mentioned, or when any of its individual capabilities are the trigger: \"object storage\" or \"S3\", \"buckets\", \"serverless functions\", \"AI gateway\", \"call an LLM\", \"logs\", \"branch logs\", \"query logs\", \"log export\", \"Loki\", \"Grafana\", \"observability\", \"telemetry\", \"postgres\", \"database\", or \"backend\". Also use when there is no Neon account yet, the user cannot sign in or provide an API key right now and needs a project they can claim later, or the user asks for a throwaway DATABASE_URL, Claimable Neon, Claimable Postgres, neon.new, claimable.neon.tech, instant Postgres, a no-signup database, temporary postgres, quick postgres, a no credit card database, or npx neon-new." }, { "identifier": "urn:air:neon.com:skill:neon-postgres-agent-platforms", "type": "application/agent-skills+md", "url": "https://neon.com/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", - "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples." + "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples." }, { "identifier": "urn:air:neon.com:skill:neon-object-storage", diff --git a/src/app/.well-known/oauth-authorization-server/claimable/route.js b/src/app/.well-known/oauth-authorization-server/claimable/route.js new file mode 100644 index 00000000000..c7ec78ae961 --- /dev/null +++ b/src/app/.well-known/oauth-authorization-server/claimable/route.js @@ -0,0 +1,7 @@ +import { buildClaimableAuthorizationServer } from 'constants/agent-discovery'; + +export const dynamic = 'force-static'; + +export function GET() { + return Response.json(buildClaimableAuthorizationServer()); +} diff --git a/src/app/api/claimable-neon/route.js b/src/app/api/claimable-neon/route.js new file mode 100644 index 00000000000..81e8be69ac2 --- /dev/null +++ b/src/app/api/claimable-neon/route.js @@ -0,0 +1,344 @@ +const DEFAULT_CLAIMABLE_NEON_ORIGIN = 'https://claimable.neon.tech'; +const ALLOWED_SERVICES = new Map([ + ['auth', 'auth'], + ['data-api', 'data_api'], +]); + +class ClaimableResponseError extends Error { + constructor(status, body) { + super('Claimable Neon rejected the request.'); + this.name = 'ClaimableResponseError'; + this.status = status; + this.body = body; + } +} + +class ClaimableConnectionError extends Error { + constructor(cause) { + super('Claimable Neon could not be reached.', { cause }); + this.name = 'ClaimableConnectionError'; + } +} + +class ClaimableContractError extends Error { + constructor(message) { + super(message); + this.name = 'ClaimableContractError'; + } +} + +class ClaimableConfigError extends Error { + constructor(message) { + super(message); + this.name = 'ClaimableConfigError'; + } +} + +const jsonResponse = (body, status = 200) => + Response.json(body, { + status, + headers: { + 'Cache-Control': 'no-store', + }, + }); + +const claimableOrigin = () => { + const configured = process.env.CLAIMABLE_NEON_ORIGIN || DEFAULT_CLAIMABLE_NEON_ORIGIN; + let url; + try { + url = new URL(configured); + } catch { + throw new ClaimableConfigError( + 'CLAIMABLE_NEON_ORIGIN must be an http(s) origin with no path, query, or fragment.' + ); + } + if ((url.protocol !== 'https:' && url.protocol !== 'http:') || configured !== url.origin) { + throw new ClaimableConfigError( + 'CLAIMABLE_NEON_ORIGIN must be an http(s) origin with no path, query, or fragment.' + ); + } + return url.origin; +}; + +const requestClaimable = async (path, init = {}) => { + const origin = claimableOrigin(); + let response; + try { + response = await fetch(`${origin}${path}`, { + ...init, + cache: 'no-store', + }); + } catch (error) { + throw new ClaimableConnectionError(error); + } + + const text = await response.text(); + let body = null; + if (text) { + try { + body = JSON.parse(text); + } catch { + throw new ClaimableContractError( + `Claimable Neon returned non-JSON content with HTTP ${response.status}.` + ); + } + } + + if (!response.ok) { + throw new ClaimableResponseError(response.status, body); + } + return body; +}; + +const exchangeAssertion = (assertion) => + requestClaimable('/v1/oauth2/token', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + assertion, + resource: `${claimableOrigin()}/`, + }), + }); + +const requireRegistration = (body) => { + if ( + !body || + typeof body.identity_assertion !== 'string' || + !body.project || + typeof body.project.id !== 'string' || + typeof body.project.branch_id !== 'string' || + typeof body.project.expires_at !== 'string' || + Number.isNaN(Date.parse(body.project.expires_at)) || + !Array.isArray(body.capabilities) || + body.capabilities.some( + (item) => !item || typeof item.capability !== 'string' || typeof item.granted !== 'boolean' + ) + ) { + throw new ClaimableContractError('Claimable Neon returned an invalid registration.'); + } + return body; +}; + +const requireToken = (body) => { + if (!body || typeof body.access_token !== 'string') { + throw new ClaimableContractError('Claimable Neon returned an invalid access token.'); + } + return body.access_token; +}; + +const requireCredentials = (body, project) => { + if ( + !body || + body.project_id !== project.id || + body.branch_id !== project.branch_id || + typeof body.database_url !== 'string' || + !body.services || + typeof body.services !== 'object' + ) { + throw new ClaimableContractError( + 'Claimable Neon returned invalid credentials for the provisioned project.' + ); + } + return body; +}; + +const requireClaim = (body) => { + let claimUrl; + try { + claimUrl = new URL(body?.verification_uri_complete); + } catch { + throw new ClaimableContractError('Claimable Neon returned an invalid claim link.'); + } + if ( + claimUrl.origin !== claimableOrigin() || + typeof body.expires_in !== 'number' || + !Number.isFinite(body.expires_in) || + body.expires_in <= 0 + ) { + throw new ClaimableContractError('Claimable Neon returned an invalid claim link.'); + } + return body; +}; + +const errorFor = (error) => { + if (error instanceof ClaimableResponseError) { + return jsonResponse( + error.body ?? { + error: { + code: 'claimable_request_failed', + message: `Claimable Neon returned HTTP ${error.status}.`, + }, + }, + error.status + ); + } + if (error instanceof ClaimableConnectionError) { + return jsonResponse( + { + error: { + code: 'claimable_service_unavailable', + message: error.message, + }, + }, + 502 + ); + } + if (error instanceof ClaimableConfigError) { + return jsonResponse( + { + error: { + code: 'invalid_configuration', + message: error.message, + }, + }, + 500 + ); + } + if (error instanceof ClaimableContractError) { + return jsonResponse( + { + error: { + code: 'invalid_claimable_response', + message: error.message, + }, + }, + 502 + ); + } + console.error('[claimable-neon] Unexpected error:', error); + return jsonResponse( + { + error: { + code: 'internal_error', + message: 'The project could not be created.', + }, + }, + 500 + ); +}; + +export async function POST(request) { + const mediaType = (request.headers.get('content-type') || '').split(';')[0].trim().toLowerCase(); + if (mediaType !== 'application/json') { + return jsonResponse( + { + error: { + code: 'invalid_request', + message: 'Content-Type must be application/json.', + }, + }, + 400 + ); + } + + let input; + try { + input = await request.json(); + } catch { + return jsonResponse( + { + error: { + code: 'invalid_request', + message: 'Request body must be valid JSON.', + }, + }, + 400 + ); + } + + const services = input?.services ?? []; + if ( + !Array.isArray(services) || + services.some((service) => typeof service !== 'string' || !ALLOWED_SERVICES.has(service)) + ) { + return jsonResponse( + { + error: { + code: 'invalid_request', + message: 'services may contain only auth and data-api.', + }, + }, + 400 + ); + } + + const requestedServices = new Set(services); + const capabilities = [ + 'postgres', + ...['data-api', 'auth'] + .filter((service) => requestedServices.has(service)) + .map((service) => ALLOWED_SERVICES.get(service)), + ]; + + let registration; + let accessToken; + try { + registration = await requestClaimable('/v1/agent/identity', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + type: 'anonymous', + capabilities, + source: 'neon_website', + }), + }); + requireRegistration(registration); + + accessToken = requireToken(await exchangeAssertion(registration.identity_assertion)); + const authorization = { Authorization: `Bearer ${accessToken}` }; + const credentials = requireCredentials( + await requestClaimable(`/v1/projects/${registration.project.id}/credentials`, { + headers: authorization, + }), + registration.project + ); + const claim = requireClaim( + await requestClaimable(`/v1/projects/${registration.project.id}/claim`, { + method: 'POST', + headers: authorization, + }) + ); + + return jsonResponse( + { + project: registration.project, + capabilities: registration.capabilities, + credentials, + claim: { + verification_uri_complete: claim.verification_uri_complete, + expires_in: claim.expires_in, + }, + }, + 201 + ); + } catch (error) { + if (registration?.project?.id) { + try { + if (!accessToken) { + accessToken = requireToken(await exchangeAssertion(registration.identity_assertion)); + } + await requestClaimable(`/v1/projects/${registration.project.id}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${accessToken}` }, + }); + } catch (cleanupError) { + console.error( + `[claimable-neon] Cleanup failed for project ${registration.project.id}:`, + cleanupError + ); + return jsonResponse( + { + error: { + code: 'claimable_cleanup_failed', + message: + 'Project setup failed and the temporary project could not be deleted. It will expire automatically.', + }, + }, + 500 + ); + } + } + return errorFor(error); + } +} diff --git a/src/app/api/claimable-neon/route.test.js b/src/app/api/claimable-neon/route.test.js new file mode 100644 index 00000000000..ecabb8b7c20 --- /dev/null +++ b/src/app/api/claimable-neon/route.test.js @@ -0,0 +1,386 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +global.fetch = vi.fn(); + +const ORIGIN = 'https://claimable.example'; + +const registration = { + registration_id: 'reg_test', + identity_assertion: 'assertion-secret', + project: { + id: 'quiet-fog-12345678', + branch_id: 'br-main', + expires_at: '2026-08-14T12:00:00.000Z', + }, + capabilities: [ + { capability: 'postgres', granted: true }, + { capability: 'data_api', granted: true }, + { capability: 'auth', granted: true }, + ], +}; + +const token = { + access_token: 'access-secret', + token_type: 'Bearer', + expires_in: 900, + scope: 'postgres.read postgres.write data_api.query auth.configure', +}; + +const credentials = { + project_id: registration.project.id, + branch_id: registration.project.branch_id, + database_url: 'postgresql://example', + expires_at: registration.project.expires_at, + services: { + data_api: { url: 'https://data-api.example/rest/v1' }, + auth: { + base_url: 'https://auth.example/api/auth', + jwks_url: 'https://auth.example/.well-known/jwks.json', + }, + }, +}; + +const claim = { + user_code: 'ABCD-2345', + verification_uri: `${ORIGIN}/claim`, + verification_uri_complete: `${ORIGIN}/claim?user_code=ABCD-2345`, + expires_in: 900, + interval: 5, +}; + +const jsonResponse = (body, init) => + new Response(JSON.stringify(body), { + status: init?.status ?? 200, + headers: { 'Content-Type': 'application/json' }, + }); + +describe('/api/claimable-neon', () => { + let POST; + + beforeEach(async () => { + vi.clearAllMocks(); + vi.resetModules(); + process.env.CLAIMABLE_NEON_ORIGIN = ORIGIN; + ({ POST } = await import('./route.js')); + }); + + afterEach(() => { + delete process.env.CLAIMABLE_NEON_ORIGIN; + }); + + it('provisions requested services and returns credentials plus a claim URL', async () => { + global.fetch + .mockResolvedValueOnce(jsonResponse(registration)) + .mockResolvedValueOnce(jsonResponse(token)) + .mockResolvedValueOnce(jsonResponse(credentials)) + .mockResolvedValueOnce(jsonResponse(claim)); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: ['auth', 'data-api'] }), + }) + ); + + expect(response.status).toBe(201); + expect(response.headers.get('Cache-Control')).toBe('no-store'); + expect(await response.json()).toEqual({ + project: registration.project, + capabilities: registration.capabilities, + credentials, + claim: { + verification_uri_complete: claim.verification_uri_complete, + expires_in: claim.expires_in, + }, + }); + + expect(global.fetch).toHaveBeenNthCalledWith( + 1, + `${ORIGIN}/v1/agent/identity`, + expect.objectContaining({ + method: 'POST', + body: JSON.stringify({ + type: 'anonymous', + capabilities: ['postgres', 'data_api', 'auth'], + source: 'neon_website', + }), + }) + ); + expect(global.fetch).toHaveBeenNthCalledWith( + 3, + `${ORIGIN}/v1/projects/${registration.project.id}/credentials`, + expect.objectContaining({ + headers: expect.objectContaining({ Authorization: `Bearer ${token.access_token}` }), + }) + ); + expect(global.fetch).toHaveBeenNthCalledWith( + 4, + `${ORIGIN}/v1/projects/${registration.project.id}/claim`, + expect.objectContaining({ method: 'POST' }) + ); + }); + + it('rejects unknown services before provisioning', async () => { + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: ['functions'] }), + }) + ); + + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_request', + message: 'services may contain only auth and data-api.', + }, + }); + expect(global.fetch).not.toHaveBeenCalled(); + }); + + it('rejects non-JSON content types before provisioning', async () => { + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'text/plain' }, + body: '{}', + }) + ); + + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_request', + message: 'Content-Type must be application/json.', + }, + }); + expect(global.fetch).not.toHaveBeenCalled(); + }); + + it('returns 502 when registration capabilities cannot be rendered', async () => { + global.fetch + .mockResolvedValueOnce( + jsonResponse({ + ...registration, + capabilities: [{}], + }) + ) + .mockResolvedValueOnce(jsonResponse(token)) + .mockResolvedValueOnce(new Response(null, { status: 204 })); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(502); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_claimable_response', + message: 'Claimable Neon returned an invalid registration.', + }, + }); + expect(global.fetch).toHaveBeenNthCalledWith( + 3, + `${ORIGIN}/v1/projects/${registration.project.id}`, + expect.objectContaining({ + method: 'DELETE', + headers: expect.objectContaining({ Authorization: `Bearer ${token.access_token}` }), + }) + ); + }); + + it('preserves structured Claimable Neon errors', async () => { + const upstreamError = { + error: { + code: 'rate_limit_exceeded', + origin: 'service', + message: 'Too many projects were created from this client.', + retryable: true, + request_id: 'req_test', + }, + }; + global.fetch.mockResolvedValueOnce(jsonResponse(upstreamError, { status: 429 })); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(429); + expect(await response.json()).toEqual(upstreamError); + }); + + it('returns 502 when Claimable Neon cannot be reached', async () => { + global.fetch.mockRejectedValueOnce(new Error('ECONNREFUSED')); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(502); + expect(await response.json()).toEqual({ + error: { + code: 'claimable_service_unavailable', + message: 'Claimable Neon could not be reached.', + }, + }); + }); + + it('returns 502 when the claim URL is not on the Claimable origin', async () => { + global.fetch + .mockResolvedValueOnce(jsonResponse(registration)) + .mockResolvedValueOnce(jsonResponse(token)) + .mockResolvedValueOnce(jsonResponse(credentials)) + .mockResolvedValueOnce( + jsonResponse({ + ...claim, + verification_uri_complete: 'https://example.invalid/claim?user_code=ABCD-2345', + }) + ) + .mockResolvedValueOnce(new Response(null, { status: 204 })); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(502); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_claimable_response', + message: 'Claimable Neon returned an invalid claim link.', + }, + }); + expect(global.fetch).toHaveBeenNthCalledWith( + 5, + `${ORIGIN}/v1/projects/${registration.project.id}`, + expect.objectContaining({ + method: 'DELETE', + headers: expect.objectContaining({ Authorization: `Bearer ${token.access_token}` }), + }) + ); + }); + + it('returns 502 when the claim link expiry is not a positive duration', async () => { + global.fetch + .mockResolvedValueOnce(jsonResponse(registration)) + .mockResolvedValueOnce(jsonResponse(token)) + .mockResolvedValueOnce(jsonResponse(credentials)) + .mockResolvedValueOnce(jsonResponse({ ...claim, expires_in: -1 })) + .mockResolvedValueOnce(new Response(null, { status: 204 })); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(502); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_claimable_response', + message: 'Claimable Neon returned an invalid claim link.', + }, + }); + expect(global.fetch).toHaveBeenNthCalledWith( + 5, + `${ORIGIN}/v1/projects/${registration.project.id}`, + expect.objectContaining({ method: 'DELETE' }) + ); + }); + + it('deletes the remote project when setup fails after registration', async () => { + const upstreamError = { + error: { + code: 'upstream_unavailable', + message: 'Credentials are temporarily unavailable.', + }, + }; + global.fetch + .mockResolvedValueOnce(jsonResponse(registration)) + .mockResolvedValueOnce(jsonResponse(token)) + .mockResolvedValueOnce(jsonResponse(upstreamError, { status: 503 })) + .mockResolvedValueOnce(new Response(null, { status: 204 })); + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(503); + expect(await response.json()).toEqual(upstreamError); + expect(global.fetch).toHaveBeenNthCalledWith( + 4, + `${ORIGIN}/v1/projects/${registration.project.id}`, + expect.objectContaining({ + method: 'DELETE', + headers: expect.objectContaining({ Authorization: `Bearer ${token.access_token}` }), + }) + ); + }); + + it('rejects a CLAIMABLE_NEON_ORIGIN that is not a bare origin', async () => { + process.env.CLAIMABLE_NEON_ORIGIN = 'https://claimable.example/v1'; + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(500); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_configuration', + message: + 'CLAIMABLE_NEON_ORIGIN must be an http(s) origin with no path, query, or fragment.', + }, + }); + expect(global.fetch).not.toHaveBeenCalled(); + }); + + it('rejects a CLAIMABLE_NEON_ORIGIN that is not a URL', async () => { + process.env.CLAIMABLE_NEON_ORIGIN = 'claimable.example'; + + const response = await POST( + new Request('https://neon.com/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [] }), + }) + ); + + expect(response.status).toBe(500); + expect(await response.json()).toEqual({ + error: { + code: 'invalid_configuration', + message: + 'CLAIMABLE_NEON_ORIGIN must be an http(s) origin with no path, query, or fragment.', + }, + }); + expect(global.fetch).not.toHaveBeenCalled(); + }); +}); diff --git a/src/app/claimable-neon/page.jsx b/src/app/claimable-neon/page.jsx new file mode 100644 index 00000000000..4b2d0a290a1 --- /dev/null +++ b/src/app/claimable-neon/page.jsx @@ -0,0 +1,14 @@ +import ClaimableNeon from 'components/pages/claimable-neon/claimable-neon'; +import Layout from 'components/shared/layout'; +import SEO_DATA from 'constants/seo-data'; +import getMetadata from 'utils/get-metadata'; + +export const metadata = getMetadata(SEO_DATA.claimableNeon); + +const ClaimableNeonPage = () => ( + + + +); + +export default ClaimableNeonPage; diff --git a/src/components/pages/claimable-neon/claimable-neon.jsx b/src/components/pages/claimable-neon/claimable-neon.jsx new file mode 100644 index 00000000000..cf6cdf14bb7 --- /dev/null +++ b/src/components/pages/claimable-neon/claimable-neon.jsx @@ -0,0 +1,547 @@ +'use client'; + +import PropTypes from 'prop-types'; +import { useEffect, useRef, useState } from 'react'; + +import Button from 'components/shared/button'; +import Container from 'components/shared/container'; +import Link from 'components/shared/link'; +import useCopyToClipboard from 'hooks/use-copy-to-clipboard'; + +const SERVICES = [ + { + id: 'data-api', + title: 'Data API', + description: 'Query the database over HTTPS. Stays enabled after claim.', + }, + { + id: 'auth', + title: 'Managed Better Auth', + description: 'Add authentication. Stays enabled after claim.', + }, +]; + +const CODE_EXAMPLES = { + agent: `GET https://neon.com/auth.md + +POST https://claimable.neon.tech/v1/agent/identity +Content-Type: application/json + +{ + "type": "anonymous", + "capabilities": ["postgres", "data_api", "auth"] +}`, + cli: `npm i -g neon@latest +neon claim create \\ + --service data-api \\ + --service auth \\ + --env-pull + +neon branches list +neon claim accept --no-open`, + config: `import { defineConfig } from '@neon/config/v1'; + +export default defineConfig({ + auth: true, + dataApi: true, +});`, +}; + +const CopyButton = ({ value, label = 'Copy', ariaLabel }) => { + const { isCopied, handleCopy } = useCopyToClipboard(1600); + + return ( + + ); +}; + +CopyButton.propTypes = { + value: PropTypes.string.isRequired, + label: PropTypes.string, + ariaLabel: PropTypes.string, +}; + +const Credential = ({ label, value }) => ( +
+
+ {label} + +
+ + {value} + +
+); + +Credential.propTypes = { + label: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, +}; + +const CAPABILITY_LABELS = { + postgres: 'Lakebase Postgres', + data_api: 'Data API', + auth: 'Managed Better Auth', +}; + +const DENIED_REASON_COPY = { + requires_claim: 'Claim the project to enable it.', +}; + +const capabilityLabel = (name) => CAPABILITY_LABELS[name] ?? name.replaceAll('_', ' '); + +const provisionErrorMessage = (error) => { + if (!(error instanceof Error)) return 'The project could not be created.'; + if (error.name === 'TypeError' || error.message === 'Failed to fetch') { + return 'The project could not be created. Check your connection and try again.'; + } + return error.message; +}; + +const Capability = ({ name, granted }) => ( + + {capabilityLabel(name)} + +); + +Capability.propTypes = { + name: PropTypes.string.isRequired, + granted: PropTypes.bool.isRequired, +}; + +const ProvisionResult = ({ result, onReset }) => { + const headingRef = useRef(null); + const { capabilities, claim, credentials, project } = result; + const formatTime = (value) => + new Intl.DateTimeFormat(undefined, { + dateStyle: 'medium', + timeStyle: 'short', + }).format(new Date(value)); + const expiresAt = formatTime(project.expires_at); + const claimExpiresAt = formatTime(Date.now() + claim.expires_in * 1000); + const granted = new Set( + capabilities.filter(({ granted: isGranted }) => isGranted).map(({ capability }) => capability) + ); + const denied = capabilities.filter(({ granted: isGranted }) => !isGranted); + const stayEnabled = [ + granted.has('auth') ? 'Managed Better Auth' : null, + granted.has('data_api') ? 'the Data API' : null, + ].filter(Boolean); + const stayEnabledSentence = + stayEnabled.length === 0 + ? '' + : stayEnabled.length === 1 + ? ` ${stayEnabled[0][0].toUpperCase()}${stayEnabled[0].slice(1)} stays enabled.` + : ` ${stayEnabled.join(' and ')} stay enabled.`; + + useEffect(() => { + headingRef.current?.focus(); + }, []); + + return ( +
+
+
+
+

Project ready

+

+ Connect your agent +

+
+ + {project.id} + +
+ +
+ {capabilities.map(({ capability, granted: isGranted }) => ( + + ))} +
+ {denied.length > 0 && ( +
    + {denied.map(({ capability, reason }) => ( +
  • + {capabilityLabel(capability)} was not granted + {DENIED_REASON_COPY[reason] ? `. ${DENIED_REASON_COPY[reason]}` : '.'} +
  • + ))} +
+ )} + +
+ + {credentials.services.data_api?.url && ( + + )} + {credentials.services.auth?.base_url && ( + + )} + +
+ +
+

+ Copy these values now. This page will not show them again. The claim link expires at{' '} + {claimExpiresAt}. If it expires, create another project from this page. Opening the claim + link does not freeze access. Continuing to Neon on the claim page rotates{' '} + DATABASE_URL. After the transfer finishes, pull a new one from the Neon + console. + {stayEnabledSentence} The project itself expires on {expiresAt}. +

+
+ + +
+
+
+ ); +}; + +ProvisionResult.propTypes = { + onReset: PropTypes.func.isRequired, + result: PropTypes.shape({ + capabilities: PropTypes.arrayOf( + PropTypes.shape({ + capability: PropTypes.string.isRequired, + granted: PropTypes.bool.isRequired, + reason: PropTypes.string, + }) + ).isRequired, + claim: PropTypes.shape({ + expires_in: PropTypes.number.isRequired, + verification_uri_complete: PropTypes.string.isRequired, + }).isRequired, + credentials: PropTypes.shape({ + database_url: PropTypes.string.isRequired, + services: PropTypes.shape({ + data_api: PropTypes.shape({ url: PropTypes.string }), + auth: PropTypes.shape({ base_url: PropTypes.string }), + }).isRequired, + }).isRequired, + project: PropTypes.shape({ + id: PropTypes.string.isRequired, + expires_at: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, +}; + +const Provisioner = () => { + const [selectedServices, setSelectedServices] = useState(new Set()); + const [state, setState] = useState({ status: 'idle' }); + + const toggleService = (service) => { + setSelectedServices((current) => { + const next = new Set(current); + if (next.has(service)) next.delete(service); + else next.add(service); + return next; + }); + }; + + const createProject = async () => { + setState({ status: 'loading' }); + try { + const response = await fetch('/api/claimable-neon', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ services: [...selectedServices] }), + }); + const body = await response.json(); + if (!response.ok) { + throw new Error( + typeof body?.error?.message === 'string' + ? body.error.message + : `Project creation failed with HTTP ${response.status}.` + ); + } + setState({ status: 'success', result: body }); + } catch (error) { + setState({ + status: 'error', + message: provisionErrorMessage(error), + }); + } + }; + + if (state.status === 'success') { + return setState({ status: 'idle' })} />; + } + + return ( +
+
+
+

Provision from this page

+

Choose your backend

+
+ +
+
+
+

Lakebase Postgres

+

+ A temporary database is always included. +

+
+ + Included + +
+ + {SERVICES.map((service) => { + const isSelected = selectedServices.has(service.id); + return ( + + ); + })} +
+ + {state.status === 'error' && ( +
+ {state.message} +
+ )} + + + +

+ No account or payment details required. Unclaimed projects expire in 72 hours and are capped + at 100 MB storage and 1 GB transfer. +

+
+ ); +}; + +const InterfaceCard = ({ eyebrow, title, description, code }) => ( +
+
+

{eyebrow}

+ +
+

{title}

+

{description}

+
+
+        {code}
+      
+
+
+); + +InterfaceCard.propTypes = { + eyebrow: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + code: PropTypes.string.isRequired, +}; + +const ClaimableNeon = () => ( + <> +
+
+ +
+
+
+ + Claimable Neon +
+

+ A project when your agent needs one. +

+

+ Agents can provision a Neon project before a human creates an account. Start building, + then claim the project into a Neon organization before it expires. +

+
+ + + Read the docs + +
+
+ {[ + ['01', 'Provision', 'Get scoped credentials'], + ['02', 'Build', 'Use standard Postgres tools'], + ['03', 'Claim', 'Transfer to your organization'], + ].map(([number, title, description]) => ( +
+ {number} +

{title}

+

{description}

+
+ ))} +
+
+
+ +
+
+
+
+ +
+ +
+

+ One service, three interfaces +

+

+ auth.md, the Neon CLI and neon.ts +

+

+ The same scoped agent credential works through auth.md, the Neon CLI, and{' '} + neon.ts. +

+
+
+ + + +
+
+
+ +
+ +
+
+

Claim

+

+ One project, a claim link, an expiry +

+
+
+ {[ + [ + 'Scoped from the first request', + 'The service creates one project and issues credentials for that project.', + ], + [ + 'Human ownership starts at claim', + 'A short-lived claim link starts a project transfer into the Neon organization selected by the human.', + ], + [ + 'Unclaimed projects expire', + 'Unclaimed projects expire in 72 hours and are capped at 100 MB storage and 1 GB transfer. Claim the project before then to keep it. Claiming rotates DATABASE_URL; Auth and the Data API stay enabled.', + ], + ].map(([title, description], index) => ( +
+ 0{index + 1} +
+

{title}

+

{description}

+
+
+ ))} +
+
+
+
+ +); + +export default ClaimableNeon; diff --git a/src/components/pages/doc/cli-reference/cli-command-index/groups.js b/src/components/pages/doc/cli-reference/cli-command-index/groups.js index 58997649f28..50088b6dba0 100644 --- a/src/components/pages/doc/cli-reference/cli-command-index/groups.js +++ b/src/components/pages/doc/cli-reference/cli-command-index/groups.js @@ -51,6 +51,7 @@ const GROUP_OF = { mcp: 'setup', skills: 'setup', plugins: 'setup', + claim: 'setup', }; // Commands documented as a section of another command's page instead of a diff --git a/src/components/pages/doc/cli-reference/cli-command-index/meta.js b/src/components/pages/doc/cli-reference/cli-command-index/meta.js index 9551a89c452..f20b619f45b 100644 --- a/src/components/pages/doc/cli-reference/cli-command-index/meta.js +++ b/src/components/pages/doc/cli-reference/cli-command-index/meta.js @@ -50,6 +50,10 @@ const META = { desc: 'Install the Neon plugin (skills plus MCP) into your coding agents.', examples: ['neon plugins', 'neon plugins -y', 'neon plugins --global'], }, + claim: { + desc: 'Create and claim a temporary project without an account.', + examples: ['neon claim create --env-pull', 'neon claim accept'], + }, completion: { desc: 'Generate a shell completion script.' }, projects: { desc: 'Manage projects.', examples: ['neon projects list'] }, branches: { diff --git a/src/constants/agent-discovery.js b/src/constants/agent-discovery.js index ab47ba604fa..12fd4c24ab0 100644 --- a/src/constants/agent-discovery.js +++ b/src/constants/agent-discovery.js @@ -37,6 +37,19 @@ const NEON_API = { docsUrl: 'https://neon.com/docs/reference/api', }; +// A path issuer avoids publishing Claimable metadata at neon.com's apex. +const CLAIMABLE = { + issuer: 'https://neon.com/claimable', + skillUrl: 'https://neon.com/auth.md', + resource: 'https://claimable.neon.tech/', + tokenEndpoint: 'https://claimable.neon.tech/v1/oauth2/token', + revocationEndpoint: 'https://claimable.neon.tech/v1/oauth2/revoke', + jwksUri: 'https://claimable.neon.tech/.well-known/jwks.json', + identityEndpoint: 'https://claimable.neon.tech/v1/agent/identity', + claimEndpoint: 'https://claimable.neon.tech/v1/agent/identity/claim', + authMarkdownPath: 'public/auth.md', +}; + // ── Payload builders ─────────────────────────────────────────────────────── // Each builder returns the exact JSON body served at the corresponding path. // The route handlers are thin wrappers around these so the verifier can assert @@ -72,9 +85,29 @@ function buildApiCatalog() { }; } +function buildClaimableAuthorizationServer() { + return { + issuer: CLAIMABLE.issuer, + token_endpoint: CLAIMABLE.tokenEndpoint, + revocation_endpoint: CLAIMABLE.revocationEndpoint, + jwks_uri: CLAIMABLE.jwksUri, + grant_types_supported: ['urn:ietf:params:oauth:grant-type:jwt-bearer'], + token_endpoint_auth_methods_supported: ['none'], + response_types_supported: [], + agent_auth: { + skill: CLAIMABLE.skillUrl, + identity_endpoint: CLAIMABLE.identityEndpoint, + claim_endpoint: CLAIMABLE.claimEndpoint, + identity_types_supported: ['anonymous'], + }, + }; +} + module.exports = { MCP_SERVER, NEON_API, + CLAIMABLE, buildMcpServerCard, buildApiCatalog, + buildClaimableAuthorizationServer, }; diff --git a/src/constants/links.js b/src/constants/links.js index 3471b21c39b..880385b335a 100644 --- a/src/constants/links.js +++ b/src/constants/links.js @@ -7,6 +7,7 @@ export default { careers: 'https://www.databricks.com/company/careers/open-positions?department=engineering&location=all&itm_source=www&itm_category=company&itm_page=engineering-at-databricks&itm_location=body&itm_component=hero&itm_offer=open-positions', caseStudies: '/case-studies', + claimableNeon: '/claimable-neon', cli: '/cli', contactSales: '/contact-sales', enterprise: '/enterprise', @@ -118,5 +119,4 @@ export default { apiReference: '/docs/reference/api', bugBounty: 'https://hackerone.com/neon_bbp', bookMeeting: 'https://calendly.com/d/cm8j-8yw-fq8', - claimablePostgres: 'https://neon.new/', }; diff --git a/src/constants/seo-data.js b/src/constants/seo-data.js index 98a836b5c87..63a6cc02769 100644 --- a/src/constants/seo-data.js +++ b/src/constants/seo-data.js @@ -51,6 +51,12 @@ export default { pathname: LINKS.caseStudies, imagePath: '/images/social-previews/case-studies.jpg', }, + claimableNeon: { + title: 'Claimable Neon for agents — Neon', + description: + 'Let agents provision a temporary Neon project (Lakebase Postgres, Data API, and Managed Better Auth) before a human creates a Neon account.', + pathname: LINKS.claimableNeon, + }, cli: { title: 'Your Neon workflow lives in the terminal', description: 'The Neon CLI brings the Neon backend platform to your terminal.', diff --git a/src/constants/static-md-manifest.js b/src/constants/static-md-manifest.js index 770b2b3bf0a..84a4194618e 100644 --- a/src/constants/static-md-manifest.js +++ b/src/constants/static-md-manifest.js @@ -4,7 +4,7 @@ export const STATIC_MD_PATHS = [ '/agentic-provisioning-llm-context.md', - '/docs/ai/skills/claimable-postgres/SKILL.md', + '/auth.md', '/docs/ai/skills/neon-ai-gateway/SKILL.md', '/docs/ai/skills/neon-functions/SKILL.md', '/docs/ai/skills/neon-functions/references/ai-sdk.md', @@ -24,6 +24,7 @@ export const STATIC_MD_PATHS = [ '/docs/ai/skills/neon-postgres-egress-optimizer/SKILL.md', '/docs/ai/skills/neon-postgres/SKILL.md', '/docs/ai/skills/neon/SKILL.md', + '/docs/ai/skills/neon/references/claimable-neon.md', '/pricing.md', '/prompts/astro-serverless-prompt.md', '/prompts/connection-issues-prompt.md', diff --git a/src/scripts/generate-skills-index.test.js b/src/scripts/generate-skills-index.test.js index 4c22b384aad..c076a02f89d 100644 --- a/src/scripts/generate-skills-index.test.js +++ b/src/scripts/generate-skills-index.test.js @@ -17,8 +17,8 @@ const SKILLS = [ digest: 'sha256:abc123', }, { - name: 'claimable-postgres', - description: 'Provision instant temporary Postgres databases.', + name: 'neon-functions', + description: 'Long-running serverless Node.js HTTP functions.', digest: 'sha256:def456', }, ]; @@ -44,19 +44,19 @@ describe('buildAgentSkillsIndex', () => { it('constructs root-relative urls with root prefix', () => { const index = buildAgentSkillsIndex(SKILLS, '/.well-known/agent-skills/'); expect(index.skills[0].url).toBe('/.well-known/agent-skills/neon-postgres/SKILL.md'); - expect(index.skills[1].url).toBe('/.well-known/agent-skills/claimable-postgres/SKILL.md'); + expect(index.skills[1].url).toBe('/.well-known/agent-skills/neon-functions/SKILL.md'); }); it('constructs /docs/-prefixed urls with docs prefix', () => { const index = buildAgentSkillsIndex(SKILLS, '/docs/.well-known/agent-skills/'); expect(index.skills[0].url).toBe('/docs/.well-known/agent-skills/neon-postgres/SKILL.md'); - expect(index.skills[1].url).toBe('/docs/.well-known/agent-skills/claimable-postgres/SKILL.md'); + expect(index.skills[1].url).toBe('/docs/.well-known/agent-skills/neon-functions/SKILL.md'); }); it('preserves skill ordering from input array', () => { const index = buildAgentSkillsIndex(SKILLS, '/.well-known/agent-skills/'); expect(index.skills[0].name).toBe('neon-postgres'); - expect(index.skills[1].name).toBe('claimable-postgres'); + expect(index.skills[1].name).toBe('neon-functions'); }); }); diff --git a/src/scripts/llms-index-config.js b/src/scripts/llms-index-config.js index 127056a3643..0db2b64bf27 100644 --- a/src/scripts/llms-index-config.js +++ b/src/scripts/llms-index-config.js @@ -17,7 +17,7 @@ module.exports = { tagline: - 'Neon is the backend for apps and agents. Services include Neon Postgres, Neon Auth, Data API, Neon Functions, Object Storage, and AI Gateway. Every service is agent-ready: instant, branchable, and serverless. Neon Postgres includes autoscaling, instant restore, and scale-to-zero, and is fully compatible with any language, framework, or ORM that supports Postgres.', + 'Neon is a complete set of cloud backend primitives built around Lakebase Postgres, for developers, startups, and agent platforms, from Databricks. Services include Lakebase Postgres, Managed Better Auth, Data API, Functions, Object Storage, and AI Gateway. Lakebase Postgres on Neon includes autoscaling, instant restore, and scale-to-zero, and works with any language, framework, or ORM that supports Postgres.', intro: [ 'Neon docs are available as markdown.', @@ -27,6 +27,11 @@ module.exports = { // Quick-reference links emitted as "## Common Queries" before the section list. commonQueries: [ + { + label: + 'Need a Neon account and the user is not around: provision one now; they claim it later', + url: 'https://neon.com/auth.md', + }, { label: 'Pricing and plans', url: 'https://neon.com/pricing.md' }, { label: 'Choose a connection method (drivers, pooling, serverless)',