detectors.yaml
This page lists the keys of detectors.yaml, where you teach kraft repo connect your own conventions, and the toolchains Kraft ships. How connect proposes commands says how a proposal is made from them.
The shipped table is data. Kraft ships it with each release, and you can layer your own on top of it in $KRAFT_HOME/config/detectors.yaml (default ~/.kraft/config/). This file is optional and is not seeded, so a newer Kraft's detectors still reach you after you write one.
max_depth: 3 # how far below the root a scope can be (default 2, at most 4)
ignore_dirs: [playground] # added to the shipped list
disable: [tox] # shipped detectors to switch off, by id
detectors:
# A detector of your own: tried before the shipped ones.
- id: earthly
tier: runner
files: [Earthfile]
test:
- run: "earthly +test"
# The same id as a shipped detector replaces it, in its place.
- id: go
tier: toolchain
family: go
files: [go.mod]
test:
- run: "gotestsum ./..."
setup:
- run: "go mod download"
The file is read on every probe, with no restart. A file that does not parse fails the probe, naming the file, and kraft admin doctor reports it. Connecting a repo that is already connected reads it only for what the entry left undecided.
A detector for a task runner names the tasks to look for, and a condition for a command that depends on what else is in the directory:
detectors:
- id: bin-tools
tier: runner
files: [bin/check]
unless: [bin/rails]
tasks: script
test:
- {tasks: [bin/check], run: "./{task}"}
setup:
- {when: [{files: [package.json]}], run: "npm ci"}
The VS Code extension validates your file against detectors.schema.json. The shipped table, with a comment on each choice, is src/kraft/detectors.yaml.
Top-level keys
| Key | Type | Default | Meaning |
|---|---|---|---|
max_depth | integer, 0 to 4 | 2 | How far below the root a scope can be. |
ignore_dirs | list of strings | [] | Directory names added to the shipped list of non-project names. |
disable | list of strings | [] | Shipped detectors to switch off, by id. An id the shipped table does not have is refused. |
detectors | list of detectors | [] | Your own detectors, tried before the shipped ones. |
Detector fields
| Field | Type | Default | Meaning |
|---|---|---|---|
id | string, [a-z][a-z0-9_-]* | (required) | Once per file. Shown as where a proposal came from, and what disable names. |
tier | runner or toolchain | (required) | runner outranks a toolchain. Both outrank CI. |
files | list of globs | (required) | At least one, relative to the directory. The detector applies when any matches. A glob without / matches only the directory's own files. |
unless | list of globs | [] | The detector does not apply when any of them matches. |
contains | mapping of glob to regex | {} | Each regex must match some file its glob names. |
tasks | string | null | Which reader lists the runner's tasks: just, make, taskfile, mise, npm (package.json scripts), composer, deno, rake, pdm, poe or script (executables under script/, scripts/, bin/). |
test, setup | list of commands | [] | Tried in order. The first one that holds is the proposal. See test and setup. |
family | string | null | The ecosystem, such as js, python or jvm. A workspace root covers members of its own family. |
lockfile | boolean | false | true when files are lockfiles: a workspace member this detector matches installs on its own, and its install still stands in a stopped directory. |
workspace | list of conditions | [] | When any one holds, the directory is a workspace root. See Conditions. |
stop | boolean | false | true marks a project Kraft has no safe command for, as the shipped pyproject detector does. Where it matches and no other detector of its family does, the directory is stopped as in A Python project with no lockfile. |
reason | string | null | What connect says about a stopped directory. Required with stop. |
wrap | string with {command} | null | How a command runs in this toolchain's environment: uv run {command}. A runner's test task in the same directory that runs pytest, python or coverage bare is proposed through it. |
venv | string, a relative path | null | The virtualenv this detector's setup makes, relative to the directory: .venv. A test command another detector proposes beside it (make test, CI's python -m unittest) runs with it active, so it imports the project's dependencies, not a worker's PATH Python. |
A detector applies to a directory when any files glob matches, no unless glob does, and every contains regex matches a file its glob names.
test and setup
Each command in the list has these keys:
| Key | Type | Meaning |
|---|---|---|
run | string | Required. The command, with {task} replaced by the task found. |
tasks | list of strings | Names to look for, first present wins. |
when | list of conditions | Any one of them must hold. |
reads | list of strings | The files the command reads, shown as where the proposal came from. Left out, it is the first of the detector's files that is there. |
Conditions
A condition, in when or workspace, holds when all of what it gives holds:
files: any glob matches.contains: each glob names a file its regex matches.toml:{glob: {dotted.key: regex}}; the value at that key of a TOML file, as JSON, matches.
toml reads one table, such as project.optional-dependencies, where a regex over the whole file would run on into the tables after it. Keep a contains regex to one line ([ \t] rather than \s): one that backtracks across a large file runs the probe into its time limit.
Toolchains in the shipped table
The shipped table covers:
- Python: uv, Poetry, PDM, Pipenv, Hatch (a
[tool.hatch.envs]table or ahatch.toml),requirements.txt, tox (itspyenvironment, also beside apyproject.tomlorsetup.pywith no lockfile); Django'smanage.py test- A
requirements.txtis set up in a.venv, which ignores itself (a.gitignoreof*inside it), so no work item commits it. Arequirements-dev.txt(orrequirements_dev.txt,dev-requirements.txt) beside it is installed too, after the base file unless it includes it with-r. A task runner's or CI's test command there runs inside that venv: apythonline as.venv/bin/python, anything else with the venv first onPATH.
- A
- JavaScript and TypeScript: npm, pnpm, Yarn classic and Berry, Bun, Deno; Nx and Turborepo; npm, pnpm, Yarn and Deno workspaces
- JVM: Gradle (Android included), Maven (a multi-module build's setup installs its modules,
-DskipTests install), sbt - Ruby: Rails, RSpec, Rake
- Others: Cargo (workspaces included), Go, .NET, Composer (its install only beside a
composer.lock, which it would otherwise write), Mix (umbrellas included), Swift, Flutter and Dart, Zig, Stack and Cabal, Julia, Bazel, CMake (aCMakeLists.txtwith aproject(of its own), Meson
Related
- How connect proposes commands: what connect reads, and how it ranks what it finds.
- repos.yaml: the
setup_command,test_commandandtest_scopesfields a proposal fills in. - Repo verbs: the
kraft repo connectflags. - Doctor failures: the fix when your
detectors.yamldoes not load.