gitstalk
Docs: Checks

Checks live

What must a bean pass to land? One file, .gitstalk/checks.yml, answers it. It is read from the exact tree each check runs on, so a change to the checks is checked by its own copy. Like the approval rules and automations, it is YAML: all .gitstalk/ configuration is YAML now.

See which suite ran

Every push says which suite its check used. With no file, the default runs: node --test with a 300-second limit.

$ git push -o wait origin HEAD:refs/heads/bean/add-truncate
remote: gitstalk: new bean add-truncate received at 3f9a1c2: "Add truncate(text, n)"
remote: gitstalk: pre-land check started: your change is merged onto the sprout and the whole suite runs on that tree
remote: gitstalk: no .gitstalk/checks.yml on this tree: the repository's default suite runs: node --test (timeout 300 s)
remote: gitstalk: LANDED: add-truncate passed its pre-land check and is on the sprout as 8d41e07
With a valid file the line reads checks from .gitstalk/checks.yml and names your command, image, time limit and any environment names.

The file

.gitstalk/checks.yml
# yaml-language-server: $schema=https://gitstalk.dev/schemas/checks.json
image: node
timeout-minutes: 1
env:
  KV_LIMIT: "3"
run: [node, --test, "spec/**/*.spec.mjs"]
protected-paths:
  - data/schema.json
  - migrations/**

Keys are named the way GitHub Actions names the same things (timeout-minutes, env, kebab-case). The first line gives editors that use the YAML language server completion and checking from the file's JSON Schema.

Key Default Rules
image node Only node today (Node 25). Other languages need their own runner image; not built yet.
run [node, --test] A list of arguments, never a shell (so not npm test). Must start with node and include --test; the rest are options and test globs. Quote a glob that starts with *.
timeout-minutes 5 Up to 30, and it must come to whole seconds (0.5 is 30 s). A suite that runs out of time is run again; a pre-land check is never reported red for timing out.
timeout-seconds 300 1 to 1,800, instead of timeout-minutes (write one, not both).
protected-paths [] Patterns: * within a segment, ** across segments, a trailing / for a directory. Relative to the repository root. Every checks file and .gitstalk/policy.yml are always protected.
env none Up to 32 upper-case names with string values: quote numbers and true/false ("10"). The runner's own (PATH, HOME, CI, GIT_*, LD_*, NODE_TEST*, BWRAP*) are refused. Never put a secret here: the file is in your repository. See Environment variables.

Why run is a list

In a GitHub Actions workflow, run: is a string that a shell runs. Checks never use a shell, so a string would either mean something different here (no pipes, no &&, no shell quoting) or need a splitting rule of its own. A list says exactly what the runner starts, so run: npm test is refused with the reason, and so is a bare number in the list.

Parsing is strict, as for the approval rules: YAML 1.2 (no stays a string), no duplicate keys, no anchors, aliases or merge keys. Every problem names its line, column and key, and unknown keys are refused by name, with a guess when one is close:

Output
.gitstalk/checks.yml is invalid:
  line 2, column 1: unknown key "rnu" (did you mean "run"?)
The tree has The check
no file The default suite, and the push says so.
a valid file Its command, environment and time limit.
an invalid file Red without running anything, naming every problem with its line, column and key.

Settings, Checks

Settings, Checks shows what the next check will run. It reads the file from the stalk with the same parser the engine uses, so the page and the check cannot disagree. It is read-only: the form never edits the file. Everyone with a role can see it, with the file itself as YAML.

A repository whose checks are still in checks.toml sees the equivalent YAML and, for the owner and maintainers, a Convert to YAML button. It saves one bean, authored by you, that writes .gitstalk/checks.yml and deletes the TOML file in the same commit; it lands through the pre-land check like any change.

RunsWhat counts as green
node --test 'spec/**/*.spec.mjs'
ImageNothing is installed at check time
node
Time limit
60 s
Environment
KV_LIMIT=3
ProtectedThe checks and policy files always
.gitstalk/checks.yml, .gitstalk/checks.yaml, .gitstalk/checks.toml, .beanstalk/checks.yml, .beanstalk/checks.yaml, .beanstalk/checks.toml, .gitstalk/policy.yml, .beanstalk/policy.yml, data/schema.json, migrations/**
To change any of it, a maintainer pushes a bean that edits the file. It is never changed from this form.

Protected paths

A bean that changes a protected path is red before any test runs, unless it was pushed by the owner or a maintainer with their own personal token or SSH key. This is how an agent is kept from weakening the checks it is judged by.

$ git push -o wait origin HEAD:refs/heads/bean/schema
remote: gitstalk: changes protected paths (data/schema.json): refused for a deploy token acting for @coop
remote: gitstalk: RED: schema was not landed. Merged onto the sprout, these tests failed:
remote: gitstalk:   - data/schema.json
remote: gitstalk: ...
The refusal names the paths and the credential that pushed, then the usual red lines follow (output, fix commands). A person pushing with their own token or key is allowed, and the first line says allowed for instead.
Who pushes May change protected paths?
Owner or maintainer, with a personal token or an SSH key Yes
Writer or reader No
Agent session (MCP), whoever it acts for No
Deploy token No

The patterns come from the sprout's copy of the file, so a bean cannot unprotect itself. For rules beyond paths, such as letting comment-only changes land on their own or sending risky areas to a person, see Approval rules.

Older files: TOML and .beanstalk/

Until 14 October 2026 the file was .gitstalk/checks.toml. It still works, with the same capabilities and snake_case keys (command, timeout_seconds, protected_paths, an [env] table). A tree's checks come from the first of these it has:

  1. .gitstalk/checks.yml
  2. .gitstalk/checks.yaml
  3. .gitstalk/checks.toml
  4. the same three in .beanstalk/

Every one of them is always protected. Messages always name the file that was read. A TOML file adds a push line saying YAML is the format now. If a tree has two, the first wins and the push says the other is not read:

Output
remote: gitstalk: checks from .gitstalk/checks.yml: node --test (image node, timeout 120 s)
remote: gitstalk: .gitstalk/checks.toml is also on this tree and is not read (.gitstalk/checks.yml wins): delete it (git rm .gitstalk/checks.toml)
checks.toml checks.yml
command = ["node", "--test"] run: [node, --test]
timeout_seconds = 120 timeout-minutes: 2 or timeout-seconds: 120
protected_paths = ["migrations/**"] protected-paths: [migrations/**]
[env] then TZ = "UTC" env: then TZ: UTC

Sources