Tuning tman for go test
Silent for minutes while compiling; keep Go's own -timeout below tman's.
Recommended starting caps
| cap | start at | what it answers |
|---|---|---|
stall | 15m | hang backstop — no output and no CPU/IO activity for this long |
max-time | 20m | wall-clock budget — the only cap that bounds a run that is working but will never finish |
max-mem | unset — opt in only if it has hurt you | RSS ceiling across the process tree |
max-parallel | 2 | slots per name-and-directory bucket |
These are starting points derived from how go test behaves, not measurements of your machine. Every one of them should be replaced by a number you took from your own runs — the last section on this page is how.
alias "test" {
command "go"
args "test" "-timeout" "10m" "./..."
max-time "20m"
}go test ./... compiles every package before it runs anything, and a cold build cache means minutes of complete silence. This is the case that motivated tman's activity-aware stall detection: across 959 supervised runs, a 60-second stall backstop fired 32 times and caught no actual hang — it killed go build ./... at 60s on work that succeeded 14 other times, once taking 75 seconds.
That is why the built-in
stallis 30m and why the guidance is to size it well above the longest quiet stretch you ever expect. On Linux the compile is protected regardless — CPU jiffies advance, so tman sees a busy tree even with no output. On macOS and Windows only the root process is sampled, so the wide default is doing the work.
Let Go's timeout fire first
go test -timeout and tman's max-time answer the same question, but they answer it very differently. Go's panics the test binary and prints a full goroutine dump naming exactly what was blocked. tman's kills the tree and returns 124. The dump is worth far more, so set Go's below tman's and let it win:
| layer | value | what you get |
|---|---|---|
go test -timeout | 10m | goroutine dump naming the blocked test — diagnose from this |
max-time | 20m | backstop for a binary too wedged to panic, or a hang before the tests start |
stall | 15m | catches an idle tree; the compile is covered by activity detection on Linux |
The same layering applies to gotestsum and to -race, which roughly doubles runtime and memory — give a race build its own alias with its own max-time rather than widening the ordinary one to fit it.
Turn the starting point into a real number
Everything above is derived from how this tool behaves, not from your machine. The numbers that matter come from your own runs, and getting them takes one command:
tman status --json | jq '.runs[] | {name, exit, duration_ms}'Set max-time from the slowest successful run you are willing to wait for, with real headroom — a cap that fires on healthy work teaches everyone to raise the cap, and after a few rounds of that it bounds nothing. Set stall from the longest stretch the command legitimately produces no output and no CPU, then double it.
Exit 124, 125, and 126 are findings, not flakes. 124 is a wall-clock timeout, 125 a stall, 126 a resource cull. Widening the cap that fired is the right response only after you know why it fired — the first two times a suite trips
max-mem, the interesting question is what is holding the memory.
Frequently asked
Why did tman kill my go build with exit 125?
It did not, at the current defaults. The stall backstop is 30m and on Linux a compile counts as activity because CPU jiffies advance even with no output. If you see 125 on a Go build, you are on a config carrying the old 60s stall, or on macOS or Windows where only the root process is sampled — widen `stall`.
Should I set go test -timeout if tman already has max-time?
Yes, and lower. Go's timeout panics the test binary and prints a goroutine dump naming what was blocked; tman's kills the tree and reports 124. Setting Go's below tman's means you get the diagnosis in the normal case and keep the backstop for a binary too wedged to panic.