Detect installed LLM harnesses such as Codex, Claude Code, Gemini CLI, Cursor, and others, then resolve their known config, state, cache, install, and project paths.
harness-detect is useful when an app, agent, plugin, or developer tool needs
to adapt to the LLM harnesses already installed on a user's machine without
hardcoding one provider. Detection is data-driven from a shared JSON registry,
so the TypeScript, Go, Rust, and Python packages stay aligned.
| Language | Package | Install |
|---|---|---|
| TypeScript / Node.js | @auron-labs/harness-detect |
bun add @auron-labs/harness-detect |
| Go | github.com/auron-labs/harness-detect/packages/golang/harnessdetect |
go get github.com/auron-labs/harness-detect/packages/golang/harnessdetect |
| Rust | harness-detect |
cargo add harness-detect |
| Python | harness-detect |
pip install harness-detect |
Supported distribution targets are npm (@auron-labs/harness-detect), Go modules (github.com/auron-labs/harness-detect/packages/golang/harnessdetect, released by packages/golang/vX.Y.Z tags), crates.io (harness-detect), and PyPI (harness-detect). Before the first public release for an ecosystem, these install commands are the intended consumer coordinates and may not resolve yet.
There is no CLI binary in this repository. These packages are libraries for embedding detection in your own tools.
import { checkHarness, detectInstalledHarnesses } from "@auron-labs/harness-detect";
const installed = detectInstalledHarnesses();
console.log(installed.map((result) => result.key));
const claude = checkHarness("claude-code");
console.log(claude.installed, claude.reasons, claude.matchedPaths);package main
import (
"fmt"
"github.com/auron-labs/harness-detect/packages/golang/harnessdetect"
)
func main() {
results, err := harnessdetect.DetectInstalledHarnesses(harnessdetect.CheckOptions{})
if err != nil {
panic(err)
}
for _, result := range results {
fmt.Println(result.Key, result.Reasons)
}
}use harness_detect::{detect_installed_harnesses, CheckOptions};
let results = detect_installed_harnesses(&CheckOptions::default())?;
for result in results {
println!("{}: {:?}", result.key, result.reasons);
}
# Ok::<(), harness_detect::HarnessError>(())from harness_detect import CheckOptions, detect_installed_harnesses
for result in detect_installed_harnesses(CheckOptions()):
print(result.key, result.reasons)Privacy: Detection results can expose absolute usernames, home directories, project paths, executable paths, and harness config/state paths. Redact the resolved path entries (
paths),matchedPaths, andexecutablePathbefore sending results to logs, telemetry, bug reports, screenshots, or analytics.
A harness counts as installed when at least one of these checks matches:
- A known executable is found on
PATH. - A known config, state, cache, install, or project path exists.
The registry contains harness keys, aliases, executable names, path templates,
environment-variable notes, installation metadata, and source URLs. The
canonical registry lives at packages/data/harnesses.json and is copied into
each package for distribution.
The registry currently covers 56 harnesses.
The check APIs accept optional environment and current-working-directory overrides. Use these when scanning a sandbox, test fixture, alternate home directory, or project path instead of the current process environment.
import { checkHarness } from "@auron-labs/harness-detect";
const result = checkHarness("codex", {
env: {
HOME: "/tmp/fake-home",
PATH: "/tmp/fake-bin",
CODEX_HOME: "/tmp/fake-codex",
},
cwd: "/tmp/project",
});
console.log(result.resolvedPaths);For raw registry access, prefer the runtime APIs over direct JSON imports:
| Language | Raw registry API |
|---|---|
| TypeScript | getRawHarnessData() |
| Go | GetRawHarnessData() |
| Rust | get_harness_matrix() |
| Python | get_harness_matrix() |
If a harness is not detected:
- Confirm the harness executable is on the same
PATHvisible to your process. - Confirm the harness has created one of its known config or state paths.
- Pass explicit
envorcwdoverrides when testing against a fixture or non-standard home directory. - Check the registry entry in
packages/data/harnesses.jsonto see which executable names and paths are currently recognized.
If the registry is missing a harness or path, open an issue or pull request with a source URL for each new executable, path, or environment variable rule.
For detection issues, include the package name/version, applicable runtime
version (Node.js/Bun, Go, Rust, or Python), OS/platform, harness key or alias,
expected versus actual result, sanitized reasons, and sanitized matchedPaths
and paths (resolved-path) summaries. Include environment-root override names
and only redacted values. Do not include full environment dumps, token or
secret values, or unredacted absolute paths, usernames, or project names; see
SUPPORT.md for the complete checklist.
- Documentation home: docs/index.md
- API reference: docs/api.md
- Registry schema and configuration: docs/configuration.md
- Adding or editing harness entries: docs/harness-guide.md
- Package parity and API contract: docs/package-guide.md
- Support expectations: SUPPORT.md
- Security reporting: SECURITY.md
- Contributing: CONTRIBUTING.md
See docs/development.md for local setup and package commands. Maintainers can use docs/maintainers.md for the full verification, registry sync, release command reference, and partial release recovery.
Common root commands:
mise run verify
mise run registry:sync
mise run registry:checkReleases are managed by release-please. Use conventional commits such as
feat:, fix:, and feat!: so release notes and versions are generated
correctly. For the Go subdirectory module, the repository tag format is
packages/golang/vX.Y.Z even though consumers install it as
go get github.com/auron-labs/harness-detect/packages/golang/[email protected].