Skip to main content

Command Palette

Search for a command to run...

Origen

Configurar CloneKit en CI con origin repo clone-fast

origin repo clone-fast sustituye a git clone en los jobs de CI. En lugar de clonar desde cero, descarga un Clone kit preconstruido, una instantánea empaquetada del repositorio que Cherri Code genera para cada repositorio con CloneKit activado, y después obtiene únicamente los objetos añadidos desde que se creó el kit. Esta página muestra cómo llevar un token de Origin de corta duración al runner y ejecutar el comando en Buildkite, GitHub Actions y otros sistemas de CI.

Cómo funciona

Cada ejecución de origin repo clone-fast {owner}/{repo} [DIR] hace lo siguiente:

  1. Obtiene el manifiesto del kit desde Origin con el token de CURSOR_AUTH_TOKEN. El manifiesto enumera los artifacts del kit y el commit de su punta.
  2. Descarga los artifacts del pack desde gitcdn.origin.cursor.com y comprueba sus tamaños. Con --verify, también comprueba sus hashes durante la descarga.
  3. Los instala en el directorio de destino, que debe estar vacío.
  4. Completa el clone: obtiene los objetos añadidos desde que se creó el kit y hace checkout de la punta actual de la default branch. Con --no-top-up, el checkout se queda en la punta del kit. --bare crea un repositorio bare sin working tree.

Cuando la ruta del kit funciona, el comando imprime mode: clone-kit en stdout. Si algún paso falla, el valor por defecto --fallback auto ejecuta en su lugar un git clone normal e imprime mode: git-clone. Pasa --fallback never para salir con estado 1 en vez de eso.

El token y el checkout se comportan igual en todos los sistemas de CI:

  • Los tokens caducan como máximo a los 15 minutos y no se pueden renovar. Emite uno justo antes del clone.
  • La CLI lee el token de CURSOR_AUTH_TOKEN. Expórtalo en el shell que ejecuta origin.
  • El clone termina en la punta de la default branch. Para crear un commit concreto, ejecuta después git fetch origin SHA y git checkout SHA. Origin sirve cualquier commit alcanzable por SHA.

Requisitos previos

  • El Origin CLI en el runner. Instálalo con curl -fsSL https://downloads.cursor.com/origin/install.sh | sh, que coloca el binario en $HOME/.local/bin/origin. Los runners de Linux necesitan glibc en x64 o arm64; Alpine y otras imágenes musl no son compatibles. Los runners de macOS sí son compatibles. Consulta Install the Origin CLI.
  • bash, git, jq, curl 7.55 o posterior y openssl 1.1.1 o posterior. clone-fast usa curl para sus descargas.
  • Egress de red hacia estos hosts:
HostSe usa para
downloads.cursor.comInstalar el CLI
origin.cursor.comEl manifiesto del kit y las git operations
gitcdn.origin.cursor.comDescargas del kit
api.cursor.comEmitir tokens y solicitudes de sincronización del mirror desde una Origin App

Elige una ruta

Sistema de CIDe dónde viene el tokenSección
Buildkite, agentes hospedados o autohospedados, con Origin conectado como proveedor de repositoriosLa Agent API de Buildkite, en un hook de checkoutBuildkite
GitHub ActionsTu Origin App, en un paso del workflowGitHub Actions
GitLab CI, Jenkins, CircleCI y fleets autohospedadosTu Origin App, en el jobOtros sistemas de CI

Buildkite

Buildkite genera el token por ti. Reemplaza el git checkout predeterminado del agente por un hook de checkout que solicite un token a la Agent API de Buildkite y ejecute origin repo clone-fast.

Debes ser administrador de la organización en Buildkite para conectar Origin, y administrador de Origin para instalar la app de Buildkite.

1

Conectar Origin a Buildkite

En Buildkite, selecciona Settings > Repository Providers > Add Provider > Origin, o selecciona Connect Origin account en la página New Pipeline. Selecciona el propietario y los repositorios y luego instala la app de Buildkite. Buildkite solicita acceso de lectura al contenido del repositorio y a los pull request, y acceso de lectura y escritura a las comprobaciones. Para más detalles, consulta Origin en la documentación de Buildkite.

2

Instalar el Origin CLI en el agente

Sigue los Prerequisites, con curl, git y jq en el PATH.

3

Mantener vacío el directorio de checkout

Si el agente conserva su directorio de compilación entre builds, vacía $BUILDKITE_BUILD_CHECKOUT_PATH antes de que se ejecute el hook. clone-fast necesita un directorio vacío y recurre a git clone si encuentra archivos ahí.

4

Añadir el hook de checkout

En un agente autohospedado, guarda el siguiente script como checkout en el directorio --hooks-path del agente. En los agentes hospedados de Buildkite, distribúyelo como el hook checkout de un plugin no incorporado, o establece checkout: { skip: true } en el paso y ejecuta los mismos comandos en el command del paso. Un hook de repositorio no puede definir checkout, porque todavía no se ha hecho checkout del repositorio. Consulta Agent hooks y Git checkout en la documentación de Buildkite.

El hook solicita un token limitado al repositorio del pipeline, lo exporta como CURSOR_AUTH_TOKEN, clona con clone-fast, registra el credential helper de git con origin auth setup-git y hace checkout de $BUILDKITE_COMMIT. El token del agente llega a curl por stdin, por lo que nunca aparece en una línea de comandos:

#!/usr/bin/env bashset -euo pipefailbody=$(printf '{"repo_url":"%s"}' "$BUILDKITE_REPO")token=$(printf 'Authorization: Token %s\n' "$BUILDKITE_AGENT_ACCESS_TOKEN" \  | curl -fsS -X POST -H @- \      -H 'Content-Type: application/json' -H 'Accept: application/json' \      --data "$body" \      "${BUILDKITE_AGENT_ENDPOINT%/}/jobs/${BUILDKITE_JOB_ID}/cursor_origin_access_token" \  | jq -er '.token')# clone-fast espera owner/repo, no la clone URL.repo=${BUILDKITE_REPO#https://origin.cursor.com/}repo=${repo#git/}repo=${repo%.git}export CURSOR_AUTH_TOKEN="$token"origin repo clone-fast "$repo" "$BUILDKITE_BUILD_CHECKOUT_PATH" --verifyorigin auth setup-gitcd "$BUILDKITE_BUILD_CHECKOUT_PATH"git fetch origin "$BUILDKITE_COMMIT"git checkout -q "$BUILDKITE_COMMIT"

Cuando una compilación se inicia sin un commit, BUILDKITE_COMMIT es HEAD. Las dos líneas de git obtienen entonces el HEAD remoto y dejan el working tree en la punta de la default branch que clone-fast ya había extraído.

  • Envía $BUILDKITE_REPO sin modificar. repo_url debe coincidir exactamente con la repository URL registrada en el pipeline, incluido .git. Cualquier variación en la escritura devuelve HTTP 400.

  • El token es read-only y está limitado al repositorio del pipeline. Incluye repository:contents:read y caduca a los 15 minutos. Un job posterior, o una operación de git más de 15 minutos después de la emisión, necesita un token nuevo obtenido con la misma solicitud.

  • Reintenta ante un 503. Si la Agent API responde con HTTP 503, espera el tiempo indicado en su header Retry-After y reintenta, tal como lo hace el propio credential helper de Buildkite.

GitHub Actions y otros proveedores de CI

GitHub Actions y otros sistemas de CI emiten sus propios tokens. Creas una Origin App una sola vez, la instalas en los repositorios que clonas y le proporcionas a cada job la clave privada de la app y dos ids. El job firma un JWT de aplicación de corta duración y lo intercambia por un installation token. Para consultar la referencia completa de los fields, consulta App JWT y Crear token de acceso de instalación.

Crear una Origin App

Debes ser administrador del espacio de trabajo para instalar la app.

Registrar la app

1

Generar un par de claves Ed25519

Solo se aceptan claves Ed25519:

openssl genpkey -algorithm ED25519 -out origin-app-private.pemopenssl pkey -in origin-app-private.pem -pubout -out origin-app-public.pem
2

Crear la app y añadir la clave pública

En los ajustes de aplicaciones de Origin, crea la app y añade el contenido de origin-app-public.pem como clave de firma. Cada app admite hasta 10 claves de firma activas.

3

Copiar el App ID

El App ID aparece en la página de la app. Los App ID empiezan por app_.

Instalar la aplicación

1

Instala la aplicación en tu owner

Desde la página de instalación de la aplicación, en esos mismos ajustes, instala la aplicación en el owner que contiene los repositorios que clonas y selecciona esos repositorios.

2

Copia el installation id

El installation id aparece en la URL de la página de la instalación: /codebase/settings/apps/installations/{installationId}. Los installation ids empiezan por i_.

Almacenar las credenciales

Almacena la clave privada como un secreto en tu sistema de CI y exponla al job en la variable de entorno ORIGIN_APP_PRIVATE_KEY, con el texto PEM completo. Almacena el App ID y el installation id como variables simples: ORIGIN_APP_ID y ORIGIN_INSTALLATION_ID. Si tu sistema de CI monta los secretos como archivos, carga primero la clave con ORIGIN_APP_PRIVATE_KEY=$(cat /path/to/origin-app-private.pem).

Emitir un token en el job

La siguiente función firma el JWT de aplicación y lo intercambia por un installation token. El JWT usa alg EdDSA, establece iss y kid con el App ID y aud con origin-apps, y fija exp 15 minutos en el futuro. La referencia de App JWT sugiere una vida útil de unos cinco minutos; dado que un installation token nunca sobrevive al JWT que lo emitió, esta receta firma un JWT de 15 minutos para que el token aproveche sus 15 minutos completos. La solicitud pide repository:contents:read, que cubre clone, fetch y pull. Para push hace falta repository:contents:write, y la instalación debe haber concedido ese scope. Añade "repositoryIds":[...] al request body para limitar el token a algunos de los repositorios de la instalación.

La clave privada llega a openssl mediante un descriptor de archivo y el header bearer llega a curl por la entrada estándar, de modo que ninguno de los dos aparece en una línea de comandos, donde otros procesos del runner podrían leerlos. La función establece y exporta CURSOR_AUTH_TOKEN directamente, por lo que el token nunca se escribe en un archivo, y una emisión fallida detiene el job con set -e. Requiere bash, openssl 1.1.1 o posterior, curl 7.55 o posterior y jq:

origin_app_token() {  b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }  now=$(date +%s)  header=$(printf '{"alg":"EdDSA","kid":"%s","typ":"JWT"}' "$ORIGIN_APP_ID" | b64url)  claims=$(printf '{"iss":"%s","aud":"origin-apps","iat":%d,"exp":%d}' \    "$ORIGIN_APP_ID" "$now" "$((now + 900))" | b64url)  # openssl -rawin requiere una entrada con búsqueda de posición; la entrada de firma no contiene ningún secreto.  signing_input=$(mktemp)  trap 'rm -f "$signing_input"' EXIT  printf '%s.%s' "$header" "$claims" > "$signing_input"  signature=$(openssl pkeyutl -sign -rawin -in "$signing_input" \    -inkey <(printf '%s\n' "$ORIGIN_APP_PRIVATE_KEY") | b64url)  app_jwt="$header.$claims.$signature"  CURSOR_AUTH_TOKEN=$(printf 'Authorization: Bearer %s\n' "$app_jwt" \    | curl -fsS -X POST -H @- -H 'Content-Type: application/json' \        --data '{"scopes":["repository:contents:read"]}' \        "https://api.cursor.com/v1/origin/app/installations/${ORIGIN_INSTALLATION_ID}/access_tokens" \    | jq -er '.token')  export CURSOR_AUTH_TOKEN}

Ejecútalo justo antes del clone en un directorio vacío y, a continuación, registra el credential helper de git para que los comandos de git posteriores se autentiquen mientras CURSOR_AUTH_TOKEN sigue exportado. Sustituye acme/widgets por tu repositorio y COMMIT_SHA por el commit que tu sistema de CI expone para el build:

set -euo pipefailorigin_app_tokenorigin repo clone-fast acme/widgets . --verifyorigin auth setup-gitgit fetch origin "$COMMIT_SHA"git checkout -q "$COMMIT_SHA"

GitHub Actions

GitHub Actions usa la ruta de la Origin App, con la clave privada en un secreto de Actions y los dos ids en variables del repositorio. Como GitHub es quien dispara el workflow, el repositorio reside en GitHub y Origin lo mantiene como réplica. El workflow le pide a Origin que haga pull del commit del build, clona con clone-fast en el $GITHUB_WORKSPACE vacío y luego hace checkout de ese commit. Nunca llama a GitHub, por lo que no necesita permisos de GITHUB_TOKEN ni usa actions/checkout.

1

Añade el secreto

En tu repositorio, selecciona Settings > Secrets and variables > Actions y añade el secreto ORIGIN_APP_PRIVATE_KEY con el PEM completo de la clave privada.

2

Añade las variables

En la misma página, añade las variables de repositorio ORIGIN_APP_ID y ORIGIN_INSTALLATION_ID.

3

Añade el workflow

Guarda el siguiente workflow como .github/workflows/ci.yml, establece ORIGIN_REPO con el {owner}/{repo} de la réplica en Origin y añade tus pasos de build después del paso de clonado.

El workflow instala el CLI, emite un token, espera a que Origin replique el commit y lo clona:

name: cion:  push:    branches: [main]  pull_request:permissions: {}jobs:  build:    runs-on: ubuntu-latest    defaults:      run:        shell: bash    steps:      - name: Install the Origin CLI        run: |          curl -fsSL https://downloads.cursor.com/origin/install.sh | sh          echo "$HOME/.local/bin" >> "$GITHUB_PATH"      - name: Clone from Origin with clone-fast        env:          ORIGIN_APP_ID: ${{ vars.ORIGIN_APP_ID }}          ORIGIN_INSTALLATION_ID: ${{ vars.ORIGIN_INSTALLATION_ID }}          ORIGIN_APP_PRIVATE_KEY: ${{ secrets.ORIGIN_APP_PRIVATE_KEY }}          ORIGIN_REPO: acme/widgets          BUILD_BRANCH: ${{ github.head_ref || github.ref_name }}          BUILD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}        run: |          set -euo pipefail          origin_app_token() {            b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }            now=$(date +%s)            header=$(printf '{"alg":"EdDSA","kid":"%s","typ":"JWT"}' "$ORIGIN_APP_ID" | b64url)            claims=$(printf '{"iss":"%s","aud":"origin-apps","iat":%d,"exp":%d}' \              "$ORIGIN_APP_ID" "$now" "$((now + 900))" | b64url)            signing_input=$(mktemp)            trap 'rm -f "$signing_input"' EXIT            printf '%s.%s' "$header" "$claims" > "$signing_input"            signature=$(openssl pkeyutl -sign -rawin -in "$signing_input" \              -inkey <(printf '%s\n' "$ORIGIN_APP_PRIVATE_KEY") | b64url)            app_jwt="$header.$claims.$signature"            echo "::add-mask::$app_jwt"            CURSOR_AUTH_TOKEN=$(printf 'Authorization: Bearer %s\n' "$app_jwt" \              | curl -fsS -X POST -H @- -H 'Content-Type: application/json' \                  --data '{"scopes":["repository:contents:read"]}' \                  "https://api.cursor.com/v1/origin/app/installations/${ORIGIN_INSTALLATION_ID}/access_tokens" \              | jq -er '.token')            echo "::add-mask::$CURSOR_AUTH_TOKEN"            export CURSOR_AUTH_TOKEN          }          origin_app_token          # Origin replica GitHub con retraso. Espera hasta unos dos minutos por este commit.          body=$(printf '{"ref":"refs/heads/%s","sha":"%s","wait":true}' "$BUILD_BRANCH" "$BUILD_SHA")          printf 'Authorization: Bearer %s\n' "$CURSOR_AUTH_TOKEN" \            | curl -fsS -X POST -H @- -H 'Content-Type: application/json' --data "$body" \                "https://api.cursor.com/v1/origin/repos/${ORIGIN_REPO}:syncMirror" \            | jq -e '.synced' > /dev/null \            || { echo "Origin has not mirrored $BUILD_SHA from $BUILD_BRANCH yet" >&2; exit 1; }          origin repo clone-fast "$ORIGIN_REPO" . --verify          origin auth setup-git          git fetch origin "$BUILD_SHA"          git checkout -q "$BUILD_SHA"
  • En pull_request, el workflow compila la cabecera del pull request. github.sha es un commit de fusión que solo existe en GitHub, así que BUILD_SHA y BUILD_BRANCH usan en su lugar el head commit y la branch del pull request.
  • La solicitud de sincronización es Sincronizar réplica. Acepta el installation token, necesita repository:contents:read y devuelve 200 con "synced": true o 202 con "synced": false tras su budget de espera de unos dos minutos. Si Origin es el source of truth y GitHub es la réplica, elimina la solicitud de sincronización: el commit ya está en Origin, y Origin rechaza las solicitudes de sincronización de repositorios que no hacen pull desde una fuente upstream.
  • Ambas credentials se enmascaran. ::add-mask:: oculta el JWT de aplicación y el installation token en el registro del job.
  • Los pasos posteriores vuelven a emitir el token. Cualquier paso posterior que necesite acceso git a Origin define y llama de nuevo a la función. El token nunca se escribe en $GITHUB_ENV ni en $GITHUB_OUTPUT, que son archivos en disco.
  • Los pull request desde forks no se replican. Su head branch no está en tu repositorio. Compila esos desde GitHub.

Otros sistemas de CI

GitLab CI, Jenkins, CircleCI y los fleets autohospedados usan directamente la vía de la Origin App. Guarda la clave privada y los dos identificadores como se describe en Store the credentials; luego ejecuta la función de Mint a token in the job justo antes de origin repo clone-fast, y haz fetch y checkout del commit que tu sistema de CI expone para el build.

Verifica la primera ejecución

Ejecuta el primer job con --fallback never. Así, si falta el kit, el job falla con estado de salida 1 en lugar de ejecutar en silencio un git clone lento. Mantén el flag activo hasta que la ruta del kit funcione.

Una ejecución correcta imprime clone-kit: manifest=..., una línea de descarga por cada artifact, un bloque clone-kit timings: y clone-kit: ready DIR (head SHA) en stderr; luego mode: clone-kit en stdout, y termina con 0. El bloque de tiempos desglosa la ejecución en las fases de manifiesto, descarga, verificación y checkout. Para medir la mejora, compara ese total con el de un git clone normal del mismo repositorio en el mismo runner.

Cuando la ruta del kit no se completa, stderr muestra una única línea legible por máquina, clone-kit-result: status=fallback phase=PHASE o clone-kit-result: status=failed phase=PHASE, seguida del motivo. Con el valor predeterminado --fallback auto, stdout muestra entonces mode: git-clone.

Solución de problemas

Cada entrada comienza con la línea que muestra el registro del job.

La obtención del manifiesto devuelve 404

clone-kit-result: status=fallback phase=manifest con HTTP 404. Todavía no existe un Clone kit para el repositorio; contacta al equipo de tu cuenta de Cherri Code para que active CloneKit. Si la URL del mensaje contiene https:// dos veces, el comando recibió una clone URL en lugar de {owner}/{repo}.

La obtención del manifiesto devuelve 401

clone-kit manifest fetch failed: HTTP 401. El origin rechazó el token: ha caducado, nunca fue válido o se eliminó su instalación. Emite un nuevo token justo antes de la clonación. Con el valor predeterminado --fallback auto, el git clone de respaldo falla con el mismo código y estado de salida 128, por lo que el registro muestra ambos errores.

La obtención del manifiesto devuelve 403

clone-kit manifest fetch failed: HTTP 403. La instalación, o el token de la canalización de Buildkite, no cubre este repositorio. Vuelve a instalar la app o selecciona de nuevo los repositorios que cubre. Igual que con el 401, el git clone de respaldo falla con el mismo código y estado de salida 128.

Git pide un nombre de usuario

fatal: could not read Username for 'https://origin.cursor.com'. O la CLI está desactualizada o CURSOR_AUTH_TOKEN no está exportada en el shell que ejecuta git. Ejecuta origin update, o exporta la variable.

La clonación recurre al respaldo en la fase auth

clone-kit-result: status=fallback phase=auth con Not authenticated. CURSOR_AUTH_TOKEN no está exportada al proceso que ejecuta origin. Expórtala en el mismo shell antes del comando origin.

La emisión devuelve 401 Issuer is not authorized

401 {"code":16,"message":"Issuer is not authorized"} desde el endpoint de tokens. La afirmación iss no corresponde a un App ID registrado, o la clave de firma no está registrada en esa app. Verifica que ORIGIN_APP_ID coincida con la app y que la app incluya la clave de firma.

origin auth status informa un token válido pero la clonación falla

origin auth status deriva Token: valid o Token: caducado de la afirmación de expiración dentro de CURSOR_AUTH_TOKEN. No le pregunta a Origin si acepta el token, por lo que valid solo significa que el token no ha caducado. La CLI considera caducado un token cinco minutos antes de su afirmación de expiración. Los comandos origin rechazan un token caducado antes de hacer cualquier solicitud, y clone-fast registra clone-kit-result: status=fallback phase=auth con The injected CURSOR_AUTH_TOKEN session has expired. Emite un nuevo token y vuelve a intentarlo.

Si la ruta del kit sigue fallando, envía al equipo de tu cuenta de Cherri Code el registro del job con la línea clone-kit-result, el repositorio y la salida de origin --version.