carapace-bridge is a Go CLI tool and library that bridges shell completion from foreign completion frameworks into the carapace ecosystem. It provides uniform carapace.Action wrappers for ~20 completion backends (cobra, argcomplete, click, yargs, bash, zsh, fish, powershell, etc.) so that any shell in the carapace family can consume completions from tools built with any of those frameworks.
go build -v ./... # build all packages
go test -v -coverprofile=profile.cov ./... # run tests with coverage
gofmt -d -s . # check formatting (must produce no output)
staticcheck ./... # lint (CI installs latest before running)The CI also runs go test -v -coverprofile=profile.cov ./... and sends coverage to Coveralls. There are no _test.go files in the repository currently — tests are effectively an integration smoke test via CI build.
This project uses a Go workspace (go.work) with two modules:
| Module | Path | Purpose |
|---|---|---|
| Root | . (github.com/carapace-sh/carapace-bridge) |
Library packages — pkg/actions/bridge, pkg/bridges, pkg/choices, pkg/env |
| CLI | ./cmd (github.com/carapace-sh/carapace-bridge/cmd) |
Binary entry point — cmd/carapace-bridge/main.go |
The cmd/go.mod uses a replace directive to point at the parent: replace github.com/carapace-sh/carapace-bridge => ../
The codebase has two different meanings of "bridge" that are easy to confuse:
pkg/actions/bridge/— Completion action bridges: Functions likeActionCobra,ActionBash,ActionYargsthat invoke a target command's completion mechanism and translate its output into acarapace.Action. These are the public API that consumers import.pkg/bridges/— Shell discovery: Functions likeBash(),Zsh(),Fish()that enumerate which commands have completions registered in a given shell. These are used byActionBridge(the meta-bridge) andActionBridges(the completer for bridge names) to know what's available.
- Consumer calls
bridge.ActionCobra("kubectl", "get")(or similar) actionCommand()wraps it: if no command is provided, it creates an ad-hoc cobra command to prompt for one- The bridge action constructs env vars / CLI args specific to the target framework's completion protocol
carapace.ActionExecCommand()spawns the target command- Output callback parses the framework-specific format (tab-separated, colon-separated, directive integer, etc.)
- Returns a
carapace.Action(typicallyActionValuesDescribedorActionFilesas fallback)
-
actionCommand()adapter (carapace.go:54): Most bridge actions use this wrapper. Whencommandis empty, it creates a standalone cobra command to let the user pick a command first; when provided, it passes the command through to the inner action directly. This is the standard entry point for new bridge actions. -
Embedded shell scripts: Bridge implementations for bash, zsh, and fish embed shell snippets via
//go:embed(bash.sh,zsh.shin the capture-completion third-party package) that are written to temp files and executed in the target shell. -
Fallback to
ActionFiles(): When a bridge gets empty output from the target command, most bridges fall back tocarapace.ActionFiles(). This is deliberate — file completion is better than nothing. -
NoSpace([]rune("/=@:.,")...): Shell bridges (bash, zsh, fish) add NoSpace for common separator characters since native completers often produce values ending with these.
Choices are persistent per-command preferences stored as files in $XDG_CONFIG_HOME/carapace/choices/<command>. Format: command/variant@group (e.g., kubectl/cobra@bridge). The ActionBridge meta-bridge checks choices first before falling back to CARAPACE_BRIDGES env var.
CARAPACE_BRIDGES: Comma-separated ordered list of implicit shell bridges to try (e.g.,bash,zsh,fish). Used byActionBridgeto resolve which shell bridge to use for a given command.- Each bridge action sets framework-specific env vars (e.g.,
_ARGCOMPLETE*for argcomplete,COMP_LINE/COMP_POINTfor bash,_<CMD>_COMPLETEfor click).
Shell discovery (listing which commands have completions in bash/zsh/fish) is expensive, so results are cached as JSON in $XDG_CACHE_HOME/carapace/bridges-<shell>.json with a 24-hour TTL.
To add a new completion framework bridge:
- Create a new file in
pkg/actions/bridge/<name>.go - Define
func Action<Name>(command ...string) carapace.Actionfollowing the existing pattern:- Wrap with
actionCommand(command...)(func(command ...string) carapace.Action { ... }) - Inside, use
carapace.ActionCallback→carapace.ActionExecCommand→ parse output → returncarapace.Action
- Wrap with
- Register the action in the
bridgeActionsmap inpkg/actions/bridge/bridge.go - Add a subcommand in
cmd/carapace-bridge/cmd/root.goviaaddSubCommand() - If the bridge is detectable (can probe a command to see if it uses this framework), add it to the
candidatesslice inpkg/actions/bridge/detect.go - If the bridge has a shell discovery counterpart (enumerate commands using it), add a function in
pkg/bridges/
- Import alias:
shlex "github.com/carapace-sh/carapace-shlex"— always aliased since the package name isshlexnotcarapace-shlex - Third-party code:
third_party/contains vendored external code (e.g., zsh-capture-completion) imported directly, NOT via go modules - Version injection:
main.gousesvar commit, date stringandvar version = "develop"— set via ldflags at release time by GoReleaser - Cobra
Standalone(): All bridge subcommands callcarapace.Gen(cmd).Standalone()to make them work as standalone completion providers DisableFlagParsing: true: Bridge subcommands disable cobra flag parsing since flags are forwarded to the bridged command
- No unit tests: There are zero
_test.gofiles. Testing is effectively done via the CI build step and Docker-based integration testing. Thedetect.gocheck()function creates temp dirs and runs actual commands, so it requires the target executables to be present. - Windows limitations: Shell bridges (bash, zsh, fish) return empty results on
windows(runtime.GOOS == "windows"guard inbridges/bash.go,bridges/zsh.go, etc.).ActionArgcompleteV1is deprecated specifically because it uses fd 8/9 which is unsupported on PowerShell/Windows. - Docker integration tests:
.docker/contains Docker Compose services that install tools for each framework (argcomplete, click, cobra, yargs, etc.) for integration testing. These are defined incompose.yamland per-framework YAML files. $PATHtypo: Inpkg/bridges/bash.go:102,os.Getenv("$PATH")includes the$prefix — this appears to be a bug but may work in certain environments; be cautious when editing that area.urfavecli_v1naming: Despite the name,urfavecli_v1actually bridges urfave/cli v3 (not v1), andurfaveclibridges v2. See the descriptions inbridge.go.- go.work is required: Since
go.workreferences./cmd, building the CLI module requires running from the workspace root, not fromcmd/directly.
GoReleaser handles releases on tag push. Config in .goreleaser.yml:
- Binary:
carapace-bridge - Entry point:
./cmd/carapace-bridge - Targets: linux, windows, darwin (+ termux/android with CGO)
- Publishes to: Homebrew (cask), Scoop, AUR, nfpm (deb/rpm/apk), Fury.io