Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

← All guides

Connect Origin

Verified against the Origin console, August 2026

Origin is Cursor's code forge. Its public REST API lives at https://api.cursor.com/v1/origin and authenticates with Origin App JWTs and short-lived installation access tokens (oit_…), not with Cloud Agents API keys.

A saved Cursor dashboard key (crsr_… / cursorApiKey) can call Cloud Agents and /v1/me. Origin rejects that same Bearer token. Use an Origin App.

What you get

Once connected, you can ask Kody things like:

  • "List the Origin repos this app installation can see."
  • "Show open pull requests on acme/api."
  • "What is left on this installation's Origin rate-limit budget?"

GitHub-mirrored-in repos stay outside installations. Native Origin repos and repos Origin mirrors out to GitHub are in scope.

Before you start

  • Origin is in early beta on paid Cursor plans. The Origin API is Alpha and can change; read the Origin API docs when updating an integration.
  • You need permission to create an Origin App and install it into a codebase at cursor.com/codebase.
  • Installation tokens last at most 15 minutes. Kody mints them just in time from a stored Ed25519 private key. Do not save an oit_… token as the durable secret.
  • secret_jwt_sign signs the app JWT host-side (algorithm: "EdDSA"). The private key never enters execute or package code.

Lane A: Origin App (durable)

  1. Open cursor.com/codebase/settings/apps and create an Origin App. Copy the app id (app_01…).

  2. Generate an Ed25519 key pair locally. Register only the public key on the app. Keep the PKCS#8 private key out of chat and out of git:

    openssl genpkey -algorithm ED25519 -out origin-app-private.pem
    openssl pkey -in origin-app-private.pem -pubout -out origin-app-public.pem
  3. Install the app into your codebase. Request only the scopes the task needs. repository:metadata:read is granted automatically. Typical read-only reporting uses repository:contents:read and repository:pull_requests:read; include repository:checks:read when reading check suites or runs. The install URL shape is documented on the Origin API page; the workspace admin picks the owner and repos.

  4. After install, store the installation id (i_01…) from the installation receipt sub claim, or list installations later with an app JWT.

Save the private key in Kody

Save the PKCS#8 PEM through the account secrets page — never paste it into chat:

https://kody.codes/account/secrets/new?name=originAppPrivateKey&description=Origin%20App%20Ed25519%20PKCS%238%20private%20key&allowedHosts=api.cursor.com&allowedCapabilities=secret_jwt_sign&scope=user

Approve api.cursor.com and the secret_jwt_sign capability on that page. The name originAppPrivateKey is what @kentcdodds/origin reads by default.

Save the readable ids as values

App id and installation id are not secrets. Store them as user values:

  • originAppId — the app_01… id (JWT iss and kid)
  • originInstallationId — the i_01… id used to mint installation tokens

Set originInstallationId explicitly. Do not select an installation implicitly when more than one installation is available.

Smoke test

After the secret and values exist, run this in execute. It signs an app JWT and reads the zero-cost rate-limit endpoint:

import { kody } from 'kody:runtime'

export default async function main() {
	const appId = (await kody.value_get({ name: 'originAppId', scope: 'user' }))
		?.value
	if (!appId) {
		throw new Error('Save originAppId as a user value first.')
	}
	const now = Math.floor(Date.now() / 1000)
	const { jwt } = await kody.secret_jwt_sign({
		private_key_secret_name: 'originAppPrivateKey',
		algorithm: 'EdDSA',
		header: { kid: appId },
		claims: {
			iss: appId,
			aud: 'origin-apps',
			iat: now,
			exp: now + 300,
		},
	})
	const rateLimit = await fetch('https://api.cursor.com/v1/origin/rate_limit', {
		headers: { Authorization: `Bearer ${jwt}` },
	})
	if (!rateLimit.ok) {
		throw new Error(`Origin rate_limit failed: ${String(rateLimit.status)}`)
	}
	const body = (await rateLimit.json()) as {
		resources?: { core?: { limit?: number; remaining?: number } }
	}
	return {
		ok: true,
		limit: body.resources?.core?.limit ?? null,
		remaining: body.resources?.core?.remaining ?? null,
	}
}

A 401 that says the request is missing a Bearer token usually means Origin did not accept the credential kind — confirm you are signing with the Origin App private key, not cursorApiKey.

After the smoke test passes, prefer a community helpers package (community_search for origin) over raw secret_jwt_sign + fetch in later work. Integrations are auth; the package is how agents should call Origin.

Helpers package

The Origin helpers package (community-search origin) wraps:

  • just-in-time app JWT + installation token minting
  • GET /v1/origin/rate_limit (smoke test)
  • installation and installation-repo listing
  • repo and pull-request reads
  • originRequest for unwrapped Origin paths

Fork or install that listing after the smoke test. Do not treat Origin as a second backer for Kody repos — Artifacts stays the durable home for Kody package source.

Lane B: one-off CLI user token (not durable)

After origin auth login, origin api sends a user Bearer token. That token is fine for a short local experiment. Installation tokens and CLI sessions expire; do not save them as originAppPrivateKey. Prefer Lane A for anything Kody should keep calling.

Related

Working with an agent? This guide is also plain markdown at /guides/origin.md, or load it over MCP with coding_guide_get({ guide: 'provider_origin' }).