Skip to content

C:\> Documentation

02

Ingesting your codebase

Contents

Codepanion indexes your source by receiving a gzipped tarball of your repo. You send it with a single curl call: no custom GitHub Actions, no CLI to install. You'll need an API key (or the keyless OIDC setup below); see getting your API key.

Creating the tarball

Pipe git ls-files into tar. This includes exactly the files tracked in your repo. Your .gitignore is the source of truth, so build artifacts and dependencies are excluded automatically.

bash
# Tar everything git tracks. Respects .gitignore, no extra config needed
git ls-files -z --recurse-submodules | tar -czf repo.tar.gz --null -T -

Tip: uncommitted changes won't be included, so commit (or stash to a branch) first. --recurse-submodules picks up submodule files; drop it if you only want the outer repo.

Adding context with .codepanion files

You can hand the agent extra context by committing .codepanion files anywhere in your repo: repo-wide (.codepanion), per-directory (src/payments/.codepanion), or per-file (src/payments/refund.ts.codepanion). They're indexed alongside your source, and the agent fetches the relevant ones on demand, so this is the place to record domain knowledge that isn't obvious from the code itself ("amounts are in cents," "Stripe for cards, Adyen for direct debit").

Sending the tarball

Post the gzipped archive to the ingest endpoint. Replace {tenantId} with your tenant ID: the identifier of your Codepanion account, and the only part of the URL that differs between customers.

bash
curl -X POST https://api.codepanion.app/api/ingest/{tenantId} \
  -H "Authorization: Bearer $CODEPANION_TOKEN" \
  -H "Content-Type: application/gzip" \
  -H "X-Commit-Sha: $COMMIT_SHA" \
  --data-binary @repo.tar.gz

Where to find your tenant ID

Your tenant ID is a GUID that identifies your Codepanion account. It is not shown anywhere in the app today. If you don't have it, ask your Codepanion contact and we'll give it to you. The tenant ID alone grants nothing: an ingest call still has to present a valid API key (or a keyless OIDC token from an allow-listed repository), and a key only ever works for the account it was created in.

The API returns the snapshot ID and status; indexing then runs asynchronously (chunk → embed → store):

json
{
  "snapshotId": 42,
  "status": "pending",
  "codeBase": "default",
  "environment": null,
  "name": null
}

The snapshot moves pendingindexingready as the worker picks it up, and the agent only ever searches ready snapshots, so an upload in flight never leaves it answering from half a repository. A snapshot that fails to index is marked failed and the previous ready snapshot keeps serving.

An upload is capped at 2 MB compressed per account by default, 10 MB uncompressed, and 10,000 files. A push over any of those is refused with a 413 whose message names the cap it hit, and nothing is stored. All three are raised on request: tell us the size of your repository when you onboard and we set the account's limit to fit it.

Snapshot history
Every push is recorded against its codebase with the commit SHA you sent, its environment label, its indexing status and the time it landed. That is the record Codepanion keeps of exactly which code the agent is answering from, shown here in the operator hub.
Snapshot history
Screenshot of Snapshot history. Every push is recorded against its codebase with the commit SHA you sent, its environment label, its indexing status and the time it landed. That is the record Codepanion keeps of exactly which code the agent is answering from, shown here in the operator hub.
Every push is recorded against its codebase with the commit SHA you sent, its environment label, its indexing status and the time it landed. That is the record Codepanion keeps of exactly which code the agent is answering from, shown here in the operator hub.

Tag an upload with an environment label and a snapshot name to keep QA or staging separate from prod; see environments.

Multiple repositories (codebases)

One Codepanion tenant can index more than one repository. Each upload lands in a codebase; tell us which one with the X-CodeBase header (or a codebase query parameter):

bash
curl -X POST "https://api.codepanion.app/api/ingest/$TENANT_ID" \
  -H "Authorization: Bearer $CODEPANION_TOKEN" \
  -H "Content-Type: application/gzip" \
  -H "X-Commit-Sha: $COMMIT_SHA" \
  -H "X-CodeBase: billing-service" \
  --data-binary @repo.tar.gz

Codebase names are lowercase letters, digits and hyphens (anything else is normalised, so acme/Widget API becomes acme-widget-api), and a codebase is created automatically the first time you ingest into it. Leave the header off and the upload goes to your default codebase, so single-repo setups need no configuration. With keyless OIDC ingest (below), each repository lands in a codebase named after it automatically. The agent searches across all your codebases by default and can scope an investigation to one.

One codebase per repository
Push as many repositories as you like. CI targets a codebase by its slug, and the agent searches across all of them unless you name one.
One codebase per repository
Screenshot of One codebase per repository. Push as many repositories as you like. CI targets a codebase by its slug, and the agent searches across all of them unless you name one.
Push as many repositories as you like. CI targets a codebase by its slug, and the agent searches across all of them unless you name one.

Settings → Codebases lists what you've pushed to, with a snapshot count each, and lets you create one up front rather than waiting for the first ingest. A slug is permanent, because it's the address CI and the agent use, so only the display name can be renamed. Codebases can't be deleted, because their snapshots belong to them. Environment labels are independent of codebases: a qa label applies within whichever codebase you upload to.

CI example: GitHub Actions

A complete workflow that ingests on every push to main, using plain curl:

.github/workflows/codepanion-ingest.yml
name: Ingest codebase

on:
  push:
    branches: [main]

jobs:
  ingest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Create tarball
        run: git ls-files -z --recurse-submodules | tar -czf repo.tar.gz --null -T -

      - name: Send to Codepanion
        env:
          CODEPANION_TOKEN: ${{ secrets.CODEPANION_TOKEN }}
          TENANT_ID: ${{ vars.CODEPANION_TENANT_ID }}
        run: |
          curl -X POST "https://api.codepanion.app/api/ingest/$TENANT_ID" \
            -H "Authorization: Bearer $CODEPANION_TOKEN" \
            -H "Content-Type: application/gzip" \
            -H "X-Commit-Sha: $GITHUB_SHA" \
            --data-binary @repo.tar.gz \
            --fail --silent --show-error

Store CODEPANION_TOKEN as a repository secret and CODEPANION_TENANT_ID as a repository variable.

Keyless ingest (recommended): GitHub Actions OIDC

GitHub's OpenID Connect removes the stored key. Your workflow proves its identity per run; Codepanion validates that short-lived token and checks the repository against an allowlist you manage in Settings → Keyless CI. This also removes API key rotation from the workflow.

.github/workflows/codepanion-ingest.yml
name: Ingest codebase

on:
  push:
    branches: [main]

permissions:
  id-token: write   # mint the short-lived OIDC token
  contents: read

jobs:
  ingest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: git ls-files -z --recurse-submodules | tar -czf repo.tar.gz --null -T -
      - name: Send to Codepanion (keyless)
        env:
          TENANT_ID: ${{ vars.CODEPANION_TENANT_ID }}
        run: |
          TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
            "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=codepanion-ingest" | jq -r .value)
          curl -X POST "https://api.codepanion.app/api/ingest/$TENANT_ID" \
            -H "Authorization: Bearer $TOKEN" \
            -H "Content-Type: application/gzip" \
            -H "X-Commit-Sha: $GITHUB_SHA" \
            --data-binary @repo.tar.gz --fail --silent --show-error

Add your-org/your-repo to the allowlist in Settings → Keyless CI. Keyless ingest stays off until at least one repository is listed. No repository secret needed, only the tenant ID variable.

The first accepted push binds that allowlist entry to the repository's GitHub ID, and later pushes have to come from the same repository. An owner/repo name can be renamed, transferred, or released and claimed by someone else, so the name on its own is treated as a label. If you rename or transfer a repository, remove the old entry and add the new name.

Need help getting set up?

We do the first setup on a call with you: the CI step, the connection string, and a first investigation against your real code.