Skip to content

Detect other project types

DefaultMarkers targets Go projects (.gtb/manifest.yaml, go.mod, .git). For any other ecosystem, pass your own marker slice — the walk is otherwise identical.

Supply your own markers

Both Detect and DetectFromCWD take the marker list as a plain []string:

// Node
ws, err := workspace.Detect(fs, startDir, []string{"package.json"})

// Rust
ws, err := workspace.Detect(fs, startDir, []string{"Cargo.toml"})

// Python
ws, err := workspace.Detect(fs, startDir, []string{"pyproject.toml", "setup.py"})

Each entry is joined onto the directory being checked and Stat-ed, so a marker can be a nested path (.gtb/manifest.yaml) as well as a top-level file or directory (.git).

Order matters — first match wins

Within a single directory the markers are checked in the order you give them, and the first that exists wins. Put the most specific marker first:

// A generated-project manifest should outrank a bare git root.
markers := []string{".myapp/project.toml", ".git"}

This is exactly why DefaultMarkers lists .gtb/manifest.yaml before go.mod before .git: a generated project is more specific than "any Go module", which is more specific than "any git repo".

Stop at the first boundary you hit

The walk climbs one directory at a time and returns as soon as any marker matches at the current level. In a monorepo where an inner package has its own go.mod and the repo root has .git, detecting from inside the package with DefaultMarkers stops at the package's go.mod — the nearest boundary — not the repo root. Choose the marker set that matches the boundary you actually want.

Bound the climb

By default the walk gives up after DefaultMaxDepth (100) parents. Tighten it when you only ever expect a shallow layout:

ws, err := workspace.Detect(fs, startDir, markers, workspace.WithMaxDepth(5))

If no marker is found within the bound, you get workspace.ErrNotFound.