Corigin

# docs

## overview

Corigin gives agents a Git remote for generated code.

## quickstart

### install the CLI

npm install -g @corigin/cli

### sign in from the terminal

corigin login

### create a repo

corigin init hello-corigin

### push with Git

echo "hello from corigin" > README.md
git add README.md
git commit -m "initial commit"
git push -u origin main

## cloning

Use cloning when the Corigin repo already exists.

### clone from the dashboard

Open Repos, copy the Clone URL, or open Connect for the full clone command.

git clone <clone-url> <repo-name>

### let an agent use the repo

git remote -v

Give the agent the working directory and the existing origin remote. Agents should use the existing Git remote. They should not create a second source-control surface or ask for workspace API keys.

## webhooks

Repo webhooks deliver accepted Corigin pushes to a public HTTPS endpoint.

### configure a webhook

Open a repo in the dashboard, then create a webhook from the Webhook section.

The URL must be a public HTTPS URL with a domain name. IP literals, localhost, and .localhost hosts are rejected.

Corigin returns the signing secret only when the webhook is created or replaced. Store it when it is shown.

### delivery

Corigin sends one push request after an accepted push creates a repo push event.

{
  "id": "77777777-7777-4777-8777-777777777777",
  "type": "push",
  "created_at": "2026-06-27T00:00:00.000Z",
  "repo_id": "33333333-3333-4333-8333-333333333333",
  "refs": [
    {
      "name": "refs/heads/main",
      "before": null,
      "after": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "force": false
    }
  ]
}

Requests include Corigin-Event-Id, Corigin-Event-Type, Corigin-Webhook-Timestamp, and Corigin-Webhook-Signature.

### verify the signature

The signature is HMAC SHA-256 over the timestamp, a period, and the raw request body.

import { createHmac, timingSafeEqual } from "node:crypto";
 
export function verifyCoriginWebhook(input: {
  body: Buffer;
  secret: string;
  signatureHeader: string;
  timestampHeader: string;
}) {
  const expected = createHmac("sha256", input.secret)
    .update(`${input.timestampHeader}.`)
    .update(input.body)
    .digest("hex");
  const received = input.signatureHeader.replace(/^v1=/, "");
  if (!/^[a-f0-9]{64}$/u.test(received)) return false;
 
  return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(received, "hex"));
}

## GitHub sync

GitHub sync imports a GitHub repository into Corigin and keeps branch updates flowing into the Corigin remote.

### import from GitHub

Use Add GitHub sync in the dashboard. The setup flow installs or reuses the Corigin GitHub App, authorizes repository access, and returns to the dashboard with an import picker.

Choose one authorized repository. Corigin creates a repo, names it from the GitHub repository name, and stores the GitHub connection on the new Corigin repo.

### sync behavior

GitHub push webhooks for branch create and update events queue sync runs. Each connection syncs serially; independent connections can sync in parallel.

Branch deletes are ignored. If the GitHub App installation is removed, suspended, or loses access to a repository, Corigin disables the affected sync connection.

### disconnect

Open the Corigin repo, then use Disconnect in the GitHub section. Disconnecting removes the active sync connection for that Corigin repo; it does not delete the Corigin repo.

## [v1 api](https://api.corigin.dev)

### examples

npm install @corigin/sdk

The SDK provides typed V1 API calls for repo lifecycle, repo webhook configuration, and repo-scoped Git tokens.

import { createCorigin } from "@corigin/sdk";
 
const corigin = createCorigin({ apiKey: "<workspace-api-key>" });
const repo = await corigin.repos.create({ name: "hello-corigin" });
 
console.log(repo.remote_url);
 
await corigin.repos.webhooks.put(repo.id, {
  url: "https://example.com/corigin/webhook",
});
 
const token = await corigin.repos.tokens.create({
  repo_id: repo.id,
  access: "write",
  ttl_seconds: 3600,
});

### OpenAPI spec

openapi: 3.1.0
info:
  title: Corigin API
  version: 0.1.0
  summary: >-
    API for agent-ready Git repos.
  description: >-
    Create Corigin repos, read repo metadata,
    configure push webhooks, and issue short-lived Git tokens
    for clone, fetch, and push.
servers:
  - url: https://api.corigin.dev
paths:
  /healthz:
    get:
      operationId: apiHealthz
      summary: Check API health
      security: []
      responses:
        "200":
          description: API is healthy.
          content:
            text/plain:
              schema:
                type: string
                const: ok
  /v1/repos:
    get:
      operationId: listRepos
      summary: List repos
      security:
        - WorkspaceApiKey: []
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
        - name: cursor
          in: query
          required: false
          schema:
            $ref: "#/components/schemas/RepoId"
      responses:
        "200":
          description: Repos accessible with the API key.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListReposResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
    post:
      operationId: createRepo
      summary: Create a Git repo
      description: >-
        Create an empty Corigin repo and return its Git remote
        URL. Repo names are metadata and may repeat.
      security:
        - WorkspaceApiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRepoRequest"
      responses:
        "201":
          description: Repo created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Repo"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "409":
          $ref: "#/components/responses/Conflict"
  /v1/repos/{id}:
    get:
      operationId: getRepo
      summary: Get repo metadata
      security:
        - WorkspaceApiKey: []
      parameters:
        - $ref: "#/components/parameters/RepoId"
      responses:
        "200":
          description: Repo accessible with the API key.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Repo"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      operationId: deleteRepo
      summary: Delete a repo
      description: >-
        Delete the repo from future list results and prevent new
        repo-scoped Git tokens from being issued. Existing repo
        tokens remain valid until expiry.
      security:
        - WorkspaceApiKey: []
      parameters:
        - $ref: "#/components/parameters/RepoId"
      responses:
        "204":
          description: Repo deleted.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/repos/{id}/webhook:
    get:
      operationId: getRepoWebhook
      summary: Get repo webhook
      security:
        - WorkspaceApiKey: []
      parameters:
        - $ref: "#/components/parameters/RepoId"
      responses:
        "200":
          description: Repo webhook configuration.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RepoWebhook"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      operationId: putRepoWebhook
      summary: Create or replace a repo webhook
      security:
        - WorkspaceApiKey: []
      parameters:
        - $ref: "#/components/parameters/RepoId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PutRepoWebhookRequest"
      responses:
        "200":
          description: >-
            Repo webhook configuration with generated signing
            secret.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RepoWebhookWithSecret"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      operationId: deleteRepoWebhook
      summary: Delete a repo webhook
      security:
        - WorkspaceApiKey: []
      parameters:
        - $ref: "#/components/parameters/RepoId"
      responses:
        "204":
          description: Repo webhook configuration deleted.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/repos/token:
    post:
      operationId: createRepoToken
      summary: Issue a repo-scoped Git token
      description: >-
        Issue a short-lived token for Git clone, fetch,
        or push access to one repo. Deleted repos, revoked
        API keys, and removed account access prevent new
        tokens from being issued.
      security:
        - WorkspaceApiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRepoTokenRequest"
      responses:
        "201":
          description: Repo token created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateRepoTokenResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
components:
  securitySchemes:
    WorkspaceApiKey:
      type: http
      scheme: bearer
      description: Corigin API key created in the dashboard.
  parameters:
    RepoId:
      name: id
      in: path
      required: true
      schema:
        $ref: "#/components/schemas/RepoId"
  responses:
    BadRequest:
      description: Invalid request.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing or invalid credential.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: Credential is valid but not authorized.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Conflict:
      description: Request conflicts with current account state.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    RepoId:
      type: string
      format: uuid
    Timestamp:
      type: string
      format: date-time
    RepoName:
      type: string
      minLength: 1
      maxLength: 128
    RemoteUrl:
      type: string
      description: Git remote URL returned by Corigin.
      pattern: "^corigin://[0-9a-f-]{36}$"
      example: "corigin://018f2f76-9a7b-7c2d-8a7e-0e36f7c8d002"
    Repo:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - remote_url
        - created_at
      properties:
        id:
          $ref: "#/components/schemas/RepoId"
        name:
          $ref: "#/components/schemas/RepoName"
        remote_url:
          $ref: "#/components/schemas/RemoteUrl"
        created_at:
          $ref: "#/components/schemas/Timestamp"
    ListReposResponse:
      type: object
      additionalProperties: false
      required:
        - next_cursor
        - repos
      properties:
        next_cursor:
          anyOf:
            - $ref: "#/components/schemas/RepoId"
            - type: "null"
        repos:
          type: array
          items:
            $ref: "#/components/schemas/Repo"
    CreateRepoRequest:
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          $ref: "#/components/schemas/RepoName"
    RepoWebhook:
      type: object
      additionalProperties: false
      required:
        - created_at
        - updated_at
        - url
      properties:
        created_at:
          $ref: "#/components/schemas/Timestamp"
        updated_at:
          $ref: "#/components/schemas/Timestamp"
        url:
          type: string
          format: uri
    PutRepoWebhookRequest:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          format: uri
    RepoWebhookWithSecret:
      type: object
      additionalProperties: false
      required:
        - created_at
        - updated_at
        - url
        - signing_secret
      properties:
        created_at:
          $ref: "#/components/schemas/Timestamp"
        updated_at:
          $ref: "#/components/schemas/Timestamp"
        url:
          type: string
          format: uri
        signing_secret:
          type: string
          description: >-
            Webhook HMAC signing secret returned only when the
            webhook is created or replaced.
    RepoTokenAccess:
      type: string
      enum:
        - read
        - write
    CreateRepoTokenRequest:
      type: object
      additionalProperties: false
      required:
        - repo_id
        - access
      properties:
        repo_id:
          $ref: "#/components/schemas/RepoId"
        access:
          $ref: "#/components/schemas/RepoTokenAccess"
        ttl_seconds:
          type: integer
          minimum: 60
          maximum: 43200
          default: 60
          description: Token lifetime in seconds.
    CreateRepoTokenResponse:
      type: object
      additionalProperties: false
      required:
        - token
        - expires_at
      properties:
        token:
          type: string
        expires_at:
          $ref: "#/components/schemas/Timestamp"
    Error:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - BadRequest
            - missing_authorization
            - invalid_api_key
            - repo_not_found
            - repo_deleted
            - active_repo_limit_exceeded
            - workspace_suspended
            - upstream_failure
        message:
          type: string