From 1f6004ebd08c77428bdfef0119f451f5be6dbc70 Mon Sep 17 00:00:00 2001
From: Bolaji Olajide <25608335+BolajiOlajide@users.noreply.github.com>
Date: Fri, 13 Nov 2026 17:56:14 +0100
Subject: [PATCH] Add a migration guide for the rebuilt src CLI
Covers the setup, flag, and scripting changes between the legacy src CLI and the rebuilt one, removed and renamed commands, and the changes to each command. Linked from the CLI sidebar and landing page.
---
docs/cli/index.mdx | 6 +
docs/cli/migration.mdx | 375 +++++++++++++++++++++++++++++++++++++++++
src/data/navigation.ts | 4 +
3 files changed, 385 insertions(+)
create mode 100644 docs/cli/migration.mdx
diff --git a/docs/cli/index.mdx b/docs/cli/index.mdx
index 2c962b790..c2241a81b 100644
--- a/docs/cli/index.mdx
+++ b/docs/cli/index.mdx
@@ -19,6 +19,12 @@ seoPriority: 1.0
href="./cli/quickstart"
description="A quickstart tutorial to learn about the src CLI in minutes."
/>
+
+ Update your setup and scripts for the rebuilt src CLI.
+
+
+The `src` CLI has been rebuilt. The legacy CLI, built from the [`sourcegraph/src-cli`](https://github.com/sourcegraph/src-cli) repository, is replaced by a CLI with the same name and nearly the same commands. Most interactive use keeps working. Scripts need changes if they:
+
+- Rely on `SRC_ENDPOINT` defaulting to Sourcegraph.com, or read settings from `~/src-config.json`.
+- Parse output with `-f` Go templates, `-json`, or `-c`.
+- Check exit statuses other than 0 and 1.
+- Use a command that was removed, such as `src repos delete` or `src teams`.
+- Use `-insecure-skip-verify`, `SRC_HEADERS`, or `SRC_PROXY`.
+
+This page covers each of these changes, then lists the changes to each command. Run `src --help` for the full usage of any command.
+
+## Install the CLI
+
+Install the CLI as described in the [quickstart](/cli/quickstart#installation). Then work through the sections below to update your environment, flags, and scripts.
+
+## Connect to your instance
+
+### Set `SRC_ENDPOINT`
+
+`SRC_ENDPOINT` is required. The legacy CLI used `https://sourcegraph.com` when it was unset; `src` fails with `no Sourcegraph endpoint configured` and exit status 2 instead.
+
+```sh
+export SRC_ENDPOINT=https://sourcegraph.example.com
+```
+
+The CLI no longer reads a config file. `~/src-config.json`, the `--config` flag, and the `--endpoint` flag are all gone; the legacy CLI had already deprecated them. The legacy CLI read `~/src-config.json` whenever it existed but only warned about it in `src login`, so check whether you have one:
+
+```sh
+cat ~/src-config.json
+```
+
+If it exists, or if your scripts pass `--config`, move the file's values to environment variables. Delete the file once you no longer use the legacy CLI.
+
+| Config file key | Replacement |
+| ------------------- | ------------------------------------------------------------------------------------------- |
+| `endpoint` | `SRC_ENDPOINT` |
+| `accessToken` | `SRC_ACCESS_TOKEN`, or credentials saved by `src auth login` |
+| `additionalHeaders` | `SRC_HEADER_AUTHORIZATION` for the `Authorization` header. Other headers are not supported. |
+| `proxy` | Not supported |
+
+An invalid `SRC_ENDPOINT`, such as one with stray quotes or a missing `https://`, fails with exit status 2 and quotes the value so you can spot the problem.
+
+### Sign in
+
+`src login` is now `src auth login`. `src login` still works, but prints a deprecation warning.
+
+```sh
+src auth login # OAuth device authorization (default)
+src auth login --method token # prompt for an access token
+src auth status # show the signed-in user
+src auth logout # remove saved credentials
+```
+
+- `src auth login` takes the instance only from `SRC_ENDPOINT`. The deprecated `src login SOURCEGRAPH_URL` still accepts the URL as an argument.
+- Credentials from either method are validated and saved in the OS credential store (macOS Keychain, Windows Credential Manager, or the Linux Secret Service).
+- `SRC_ACCESS_TOKEN`, when set, takes precedence over saved credentials. `src auth login` uses it unless you pass `--method oauth`.
+- `src auth status` and `src auth logout` are new.
+
+### Run in CI and scripts
+
+In CI, set `SRC_ENDPOINT` and `SRC_ACCESS_TOKEN` (see [Creating an access token](/cli/how-tos/creating-an-access-token)). When the `CI` environment variable is true, or when you pass `--non-interactive`, `src`:
+
+- Authenticates only with `SRC_ACCESS_TOKEN` or `SRC_HEADER_AUTHORIZATION`, never with saved credentials.
+- Never prompts, opens a browser, or reads the OS credential store.
+- Prints no color or other terminal styling.
+
+A command that needs a person, such as `src users prune` without `--force`, fails with exit status 3 instead of waiting for input.
+
+### Authenticating proxies and custom headers
+
+`SRC_HEADER_AUTHORIZATION` works as before: `src` sends its value as the `Authorization` header instead of an access token or saved credentials. It cannot be combined with `SRC_ACCESS_TOKEN`.
+
+These are not supported:
+
+- `SRC_HEADER_*` variables other than `SRC_HEADER_AUTHORIZATION`.
+- `SRC_HEADERS`.
+- `SRC_PROXY` and the config file's `proxy` key.
+
+### TLS certificates
+
+`src` always verifies the instance's TLS certificate. `-insecure-skip-verify` is rejected with exit status 2. To trust a private certificate authority, pass its certificate with `--ca-bundle`:
+
+```sh
+src --ca-bundle corporate-ca.pem auth login
+```
+
+`--client-cert` and `--client-key` are new, and present a client certificate for mutual TLS. These three flags work with every command and accept a PEM file or an HTTPS URL; `--client-cert` and `--ca-bundle` also accept a `keychain:` source. Pass them on each invocation; `src auth login` does not save them.
+
+### Instance policy and telemetry
+
+Before a command contacts your instance, `src` fetches the instance's CLI policy and applies it. For example, an instance can block access tokens from the CLI. When the instance is unreachable, `src` applies the last policy it fetched and adds a warning. `src auth`, `src login`, `src schema`, and `src version` don't fetch the policy.
+
+Each command that authenticates records one usage event on your instance. `--user-agent-telemetry` has no effect and `SRC_DISABLE_USER_AGENT_TELEMETRY` is ignored, since `src` never sends your operating system or architecture in its `User-Agent`.
+
+## Update flags
+
+Flags follow GNU conventions. Long flags take two dashes, such as `--name abc-org` or `--name=abc-org`, and one dash is for single-letter shorthands, such as `-o json`.
+
+Flags that the legacy command had also work with one dash, but print a deprecation warning. Several such flags share one warning:
+
+```text
+Warning: -first and -indexed are deprecated and will be removed in a future version; use --first and --indexed respectively instead.
+```
+
+Flags that are new in the rebuilt CLI work only with two dashes. Help is `--help` or `-h`, not `-help`. As before, a flag must come after the command that defines it.
+
+Every command accepts these global flags:
+
+| Flag | Purpose |
+| ---------------------------------------------- | ------------------------------------------------------------------------ |
+| `-o`, `--output` | Output format: `human` (default), `json`, or `jsonl` |
+| `-v`, `--verbose` | Print extra diagnostic output |
+| `--quiet` | Hide non-essential output, such as progress bars |
+| `--non-interactive` | Never prompt, open a browser, read the OS credential store, or use color |
+| `--ca-bundle`, `--client-cert`, `--client-key` | TLS settings; see [TLS certificates](#tls-certificates) |
+
+Since `-o` is the global `--output` flag, `src debug` names its archive with `--archive` instead.
+
+To pass an argument that starts with a dash, such as a search query, put it after `--`:
+
+```sh
+src search -- '-file:test error'
+```
+
+`src help` prints the same help as `src --help`. For a command's help, run `src --help`. `src completion bash`, `zsh`, `fish`, or `powershell` prints a shell completion script.
+
+## Update scripts
+
+### Use `--output json` instead of templates
+
+The `-f` Go template flag, `-json`, and `-c` are removed. Use `--output json` and a JSON tool such as [`jq`](https://jqlang.org/). With `--output json`, every command prints one JSON document to stdout, whether it succeeds or fails. For example, `src orgs delete --id T3JnOjE= --output json` prints:
+
+```json
+{
+ "data": {"id": "T3JnOjE=", "deleted": true},
+ "warnings": [],
+ "error": null
+}
+```
+
+- `data` holds the result, so read fields from `.data`. It is `null` when a failure has no result.
+- `warnings` lists non-fatal warnings, each with a stable `code`, such as `DEPRECATED` or `PARTIAL_RESULT`, and a `message`.
+- `error` is `null` on success. On failure, it has a `code`, `message`, `retryable`, and, when there is one, a `remediation`.
+
+`--output jsonl` prints the same document on one line. Run `src schema ` to list a command's output fields, or `src schema --output json` for its JSON Schema.
+
+Field names in the JSON are camel-cased, unlike the template fields. For example, `{{.DisplayName}}` becomes `.displayName`, and `{{.DefaultBranch.Name}}` becomes `.defaultBranch.name`. Common conversions:
+
+```sh
+# Legacy: src users get -f '{{.ID}}' -username=alice
+src users get --username alice --output json | jq -r .data.id
+
+# Legacy: src repos get -name=github.com/my/repo (printed only the ID)
+src repos get --name github.com/my/repo --output json | jq -r .data.id
+
+# Legacy: src users delete -id=$(src users get -f='{{.ID}}' -username=alice)
+src users delete --id "$(src users get --username alice --output json | jq -r .data.id)"
+
+# Legacy: src repos list -f '{{.ID}}: {{.Name}}'
+src repos list --output json | jq -r '.data.repositories[] | "\(.id): \(.name)"'
+
+# Legacy: src extsvc list -f '{{.config}}'
+src extsvc list --output json | jq -r '.data.externalServices[].config'
+
+# Legacy: src config list -f '{{range .Subjects}}{{.ID}}{{end}}'
+src config list --output json | jq -r '.data.subjects[].id'
+
+# Legacy: src search-jobs get ID -json
+src search-jobs get ID --output json | jq -r .data.state
+```
+
+Without `--output`, list commands print one name per line, matching the legacy default templates. `src repos get` is an exception: it prints the repository's details instead of only its ID.
+
+### Check exit statuses
+
+The legacy CLI exited with status 1 for most failures. `src` exits with a status for each kind of failure:
+
+| Exit status | Error code | Meaning |
+| ----------- | --------------------- | ---------------------------------------------------------------------------------------------- |
+| 0 | | Success |
+| 1 | `INTERNAL`, `UNKNOWN` | Unexpected failure |
+| 2 | `INVALID_ARGUMENT` | Invalid flags, arguments, or `SRC_ENDPOINT` |
+| 3 | `FAILED_PRECONDITION` | The environment or the instance's state prevents the command, such as no terminal for a prompt |
+| 4 | `UNAUTHENTICATED` | Missing or rejected credentials |
+| 5 | `PERMISSION_DENIED` | Signed in, but not allowed, including by the instance's CLI policy |
+| 6 | `NOT_FOUND` | A named resource, such as a user or repository, does not exist |
+| 7 | `RATE_LIMITED` | Rate limited; retry later |
+| 8 | `UNAVAILABLE` | Network failure, timeout, or the instance is unavailable; retry later |
+| 9 | `UNSUPPORTED_VERSION` | The instance does not support the request |
+| 130 | `CANCELED` | Interrupted, for example with Ctrl-C |
+
+In human output, the error and a suggested fix go to stderr. Run `src schema error` for the full error format.
+
+Several commands that printed nothing, printed `null`, or exited with status 0 when something was missing now fail. For example, `src repos get` and `src users get` fail with `NOT_FOUND` for a missing repository or user. Commands also check flags and IDs before contacting the instance, so invalid input fails with exit status 2 instead of an error from the instance. An empty list is still a success.
+
+### stdout and stderr
+
+Command results go to stdout, and warnings, progress, and errors go to stderr. Some success messages moved from stderr to stdout:
+
+- `src batch validate`: `✅ Batch spec successfully validated.`
+- `src batch preview`, `src batch apply`, and `src batch remote`: the final lines with the URL.
+- `src search-jobs cancel` and `src search-jobs delete`: the confirmation.
+
+Deprecation notices and other warnings are written to stderr as `Warning:` lines in human output, and to `warnings` with `--output json`.
+
+### Debug requests
+
+`--get-curl`, `--trace`, and `--dump-requests` work with the commands that had them, with these changes:
+
+- `--get-curl` first checks your credentials, and fails with exit status 4 when they are missing or rejected. It then prints the command's first API request as a `curl` command and exits with status 0.
+- `--trace` and `--dump-requests` write to stderr, so they work with `--output json`. `--dump-requests` doesn't print headers or credentials.
+
+## Removed commands and flags
+
+These commands and flags aren't available in the rebuilt CLI.
+
+| Legacy command or flag | Reason and replacement |
+| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `src abc` | Agentic batch change commands aren't available in the CLI. |
+| `src codeowners` | Sourcegraph 7.0 removed uploaded `CODEOWNERS` files. `CODEOWNERS` files checked into repositories still work. |
+| `src teams` | Sourcegraph 7.0 removed teams. |
+| `src debug server` | Sourcegraph 7.0 removed single-container deployments. `src debug kube` and `src debug compose` remain. |
+| `src repos delete` | Sourcegraph no longer deletes repositories through the API. Exclude the repository in its code host connection, for example with `exclude`; Sourcegraph deletes it on the next sync. |
+| `src repos add-kvp`, `update-kvp`, `delete-kvp` | Use `src repos add-metadata`, `update-metadata`, and `delete-metadata`. |
+| `src users tag`, `src users list --tag` | Sourcegraph 5.1 removed user tags. |
+| `src sbom fetch`, `src signature verify` | Sourcegraph stopped publishing SBOMs and image signatures in 7.1.0. |
+| `src extensions`, `src gateway` | Listed in the legacy help, but never implemented. |
+| `src auth token` | Not available. Set `SRC_ACCESS_TOKEN` and pass it to other tools directly. |
+| `-f` (Go templates), `-json`, `-c` | Use `--output json`. See [Use `--output json` instead of templates](#use---output-json-instead-of-templates). |
+| `--config`, `--endpoint` | Set `SRC_ENDPOINT` and `SRC_ACCESS_TOKEN`. |
+| `-insecure-skip-verify` | Use `--ca-bundle`. See [TLS certificates](#tls-certificates). |
+| `-skip-errors` on `batch new`, `repositories`, `validate`, and `remote` | It skipped a version check that is no longer needed. `src batch preview` and `src batch apply` keep `--skip-errors`. |
+
+An unknown command or flag fails with exit status 2. When you mistype a command, the error suggests the closest match.
+
+## Renamed commands and flags
+
+| Legacy | Rebuilt |
+| --------------------------------------- | ----------------------------------------------------- |
+| `src login` | `src auth login` (`src login` is deprecated) |
+| `src config edit` | `src config update` (`src config edit` is deprecated) |
+| `src debug kube -o FILE` | `src debug kube --archive FILE` |
+| `src debug compose -o FILE` | `src debug compose --archive FILE` |
+| `src code-intel upload -indexerVersion` | `src code-intel upload --indexer-version` |
+| `src search -explain-json` | `src schema search` |
+| `src version --client-only` | `src version` |
+
+## Changes by command
+
+Each command below keeps its legacy aliases, such as `src repo` and `src batches`, unless noted.
+
+### `src api`
+
+- Requests require authentication. The legacy CLI sent the request without credentials when none were configured.
+- When the response has GraphQL errors, the command prints the response and fails. A query the instance rejects exits with status 2, as before. Other errors exit with status 4, 5, or 8 when they report an authentication, permission, or availability problem, and 1 otherwise.
+- With `--output json`, `data` is the response's `data`, and GraphQL errors are in `error.details.graphqlErrors`.
+- Numbers in `--vars` are sent exactly as written. The legacy CLI rounded integers larger than 2^53.
+
+### `src batch`
+
+- `src batch exec` is not available.
+- Reading a batch spec from a terminal is an error. Pipe the batch spec in or pass its file.
+- An invalid batch spec fails with exit status 2 before `src` authenticates.
+- `src batch validate` accepts the batch spec as a `FILE` argument, as its legacy help showed. It no longer accepts `-allow-unsupported`, `-force-override-ignore`, or `-skip-errors`, which had no effect.
+- `src batch preview` and `src batch apply` no longer accept `-apply` or `-text-only`; use `--output json` or `--output jsonl` for machine-readable output. `--skip-errors` only lets the batch spec be created when steps fail in some workspaces, and reports each failure as a warning.
+- `--workspace` accepts only `auto`, `bind`, or `volume`. The legacy CLI treated other values as `auto`.
+- A batch spec with `version: 3` fails in `src batch preview` and `src batch apply`; run it with `src batch remote`.
+- A batch spec that only imports changesets doesn't need Docker or Git.
+- `src batch remote` uploads files whose names start with a dot, such as `.github`, to the right path. The legacy CLI dropped the leading dot.
+
+### `src code-intel upload`
+
+- `-indexerVersion` is now `--indexer-version`. `--indexerVersion` still works, but is deprecated.
+- `-json` is replaced by `--output json`, with the same fields.
+- `src` validates your credentials before uploading. With `--ignore-upload-failure`, rejected credentials and invalid flags still fail; only a failed upload exits with status 0, with an `UPLOAD_FAILED` warning.
+- `uploadUrl` links to the upload's page under `/-/code-graph/indexes/`.
+- `-trace` and `-insecure-skip-verify` are not available.
+
+### `src config`
+
+- `src config edit` is now `src config update`, and prints `Settings updated:` followed by the subject's ID.
+- `src config update` requires exactly one of `--property` and `--overwrite`, and exactly one of `--value` and `--value-file`. The value must be valid JSON. The legacy CLI silently preferred one flag when both were given.
+- An empty `--subject` fails with exit status 2. The legacy CLI used your own settings.
+- `src config list` shows each subject's full settings URL, and labels the instance's defaults `# Default settings:`.
+
+### `src debug`
+
+- `-o FILE` is now `--archive FILE`. A legacy `-o debug.zip` fails and points to `--archive`.
+- The commands no longer ask for confirmation. They never overwrite an existing archive.
+- They fetch the site configuration and code host connections from `SRC_ENDPOINT` with your credentials, so you must be signed in. A file the instance refuses, for example because you aren't an administrator, is left out with a warning. Pass `--no-configs` to skip both files and not contact the instance at all.
+- A file that can't be collected is left out of the archive with a warning, instead of failing the command.
+- The archive is readable only by its owner.
+- `src debug server` is removed.
+
+### `src extsvc`
+
+- `src extsvc create` requires `--name` and `--kind`, and is also available as `src extsvc add`. When given both a file and piped input, it reads the file.
+- `src extsvc edit` requires exactly one of `--id` and `--name`. `--name` fails when several external services share the name; the legacy CLI edited the first.
+- With `--rename` or `--exclude-repos` and no `CONFIG_FILE`, `src extsvc edit` no longer reads piped input. To read a configuration from stdin, pass `-`, for example `cat github.json | src extsvc edit --id ID --rename NEW_NAME -`.
+- `--exclude-repos` keeps the existing `exclude` entries and their comments.
+
+### `src lsp`
+
+- The server authenticates when it starts and exits with status 4 when credentials are missing or rejected. The legacy server started anyway.
+- Starting outside a Git checkout, or without `origin/HEAD`, exits with status 3. To set `origin/HEAD`, run `git remote set-head origin --auto`.
+- `--output json`, `--get-curl`, and the other API flags are not accepted.
+
+### `src orgs`
+
+- `src orgs list` doesn't include members. Use `src orgs get` for an organization's members.
+- `src orgs get` requires `--name`, and `src orgs delete` requires `--id`.
+- `src orgs members remove` works. The legacy command always failed.
+- `--org-id` and `--user-id` must be GraphQL IDs of an organization and a user.
+
+### `src repos`
+
+- `src repos get` prints the repository's details instead of only its ID. Use `--output json | jq -r .data.id` for the ID.
+- `src repos list --first` returns up to the number you ask for. The legacy CLI stopped at 1,000.
+- In JSON, `keyValuePairs` is now `metadata`, `updatedAt` is gone, `url` is absolute, and `defaultBranch` is `null` when there is none.
+- The metadata commands require exactly one of `--repo` and `--repo-name`. They print what changed, such as `Added team=search to github.com/my/repo`. `add-metadata` fails for a key the repository already has, and `update-metadata` for a key it doesn't have.
+
+### `src search`
+
+- Queries use the same syntax as the Sourcegraph web app. The legacy default treated patterns as regular expressions; add `patterntype:regexp` to keep that behavior.
+- `--query-file FILE` reads the query from a file, and `src search -` reads it from stdin. To search for a literal `-`, quote it: `src search '"-"'`.
+- `-json` is replaced by `--output json`, with a different shape. Line numbers are 1-based, URLs are absolute, file results don't include file contents, `ResultCount` is now `matchCount`, and each result has a `type` of `file`, `commit`, or `repository`.
+- `-stream`, `-display`, and `-less` are not available. Results are shown when the search completes; pipe them to a pager, and add `count:N` to the query to limit them.
+- Output is colored only on a terminal. `COLOR` and `COLORDIFF` are ignored, and `NO_COLOR` still disables color.
+
+### `src search-jobs`
+
+- `src search-jobs get` and `create` print the job's fields one per line instead of a tab-separated line.
+- `src search-jobs list` returns up to `--limit` jobs. The legacy CLI stopped at 100. With no jobs, it succeeds with empty output.
+- `src search-jobs logs` and `results` with `--output json` require `--out`. They download from `SRC_ENDPOINT`, so they work when the instance's external URL isn't reachable from your machine.
+- An ID that isn't a search job's GraphQL ID fails with exit status 2.
+
+### `src serve-git`
+
+- Repositories nested inside another repository's directory are not served.
+- Interrupting the server exits with status 0 instead of 130.
+
+### `src snapshot`
+
+- The commands are no longer experimental. `summary.json` has the same format, so summaries recorded by either CLI work with both.
+- `src snapshot databases`, `restore`, and `upload` don't contact the instance and need no credentials.
+- Without `--run`, `databases` and `restore` print a shell script to stdout that you can save or pipe to `sh`.
+- Failed database commands, and a failed `src snapshot test`, exit with status 3 instead of 1.
+- `src snapshot test` no longer queries monitoring alerts, which fixes it against Sourcegraph 5.11.0 and later. It counts `ERRORED` permissions sync jobs as failures.
+- `src snapshot upload` requires a Google service account key for `--credentials`, and fails when Cloud Storage rejects an upload.
+
+### `src users`
+
+- `src users list` returns each user's `id`, `username`, and `displayName` only, and non-administrators can run it. Use `src users get` for emails and organizations.
+- `src users get` requires exactly one of `--username` and `--email`, and doesn't return `siteAdmin`.
+- `src users delete` requires `--id`.
+- `src users prune` rejects `--days` below 60 with exit status 2. In CI or with `--non-interactive`, it requires `--force`.
+- `src users create` labels the reset link `Reset password URL`. With `--output json`, `resetPasswordURL` is `null` unless you pass `--reset-password-url`.
+
+### `src version`
+
+`src version` prints only the CLI's version, like the legacy `--client-only`, and doesn't accept `--client-only`. It doesn't show the version your instance recommends.
+
+## Commands with no legacy equivalent
+
+| Command | Description |
+| ------------------------ | ------------------------------------------------------------- |
+| `src auth status` | Shows the signed-in user and which credentials `src` used |
+| `src auth logout` | Removes saved credentials for the instance |
+| `src schema ` | Describes a command's JSON output, or prints its JSON Schema |
+| `src completion ` | Prints a completion script for bash, zsh, fish, or PowerShell |
diff --git a/src/data/navigation.ts b/src/data/navigation.ts
index a4c5efff0..10d9bff56 100644
--- a/src/data/navigation.ts
+++ b/src/data/navigation.ts
@@ -489,6 +489,10 @@ export const navigation: NavigationItem[] = [
href: '/cli',
sections: [
{title: 'Quickstart', href: '/cli/quickstart'},
+ {
+ title: 'Migrating from the legacy CLI',
+ href: '/cli/migration'
+ },
{title: 'Explanations', href: '/cli/explanations'},
{title: 'How-tos', href: '/cli/how-tos'},
{title: 'References', href: '/cli/references'}