Any other agent + tman
No documented pre-shell hook. Supervision comes from PATH shims plus a line in the project's instruction file, which is enough for anything invoked through a shell.
- vendor
- Aider, Amp, Windsurf, Zed, CI runners
- integration
- shims only
- hook event
- none — shims
- config
- .tman.kdl + AGENTS.md
Hooks are a convenience. The mechanism underneath them — a supervised entry point that any shell lookup resolves to — needs nothing from the agent at all, which is why it is the right default for Aider, Amp, Windsurf, Zed, a CI runner, or a tool that shipped after this page was written.
1. Install tman and adopt the project
Everything below assumes the binary is on your PATH and the repository has a .tman.kdl. That file is what scopes caps to this project, and it is also the signal several of the integrations test for before they do anything.
npm install -g @standardbeagle/tman # or the install.sh one-liner
cd your-project
tman init --shims --gitignoretman init writes a defaults block and an alias for each test or build command it can detect. Commands it cannot detect are left commented out rather than stubbed, so an alias you never filled in fails loudly instead of exiting 0 having run nothing.
What the shims actually do
tman init --shims writes small executables at the repository root — ./test, ./lint, and one per alias it detected. Each invokes tman with that alias, so the caps in .tman.kdl apply without anyone having to remember them. Anything that runs ./test is supervised: you at a prompt, a Makefile, a CI step, or an agent that shells out.
Never hand a bare relative
argv[0]like./testto an exec that does not go through a shell. A relativeargv[0]is resolved through PATH, not the working directory, and will silently find some unrelated program of the same name. From a workflow step or a language-levelexec, writesh -c "exec ./test".
Aliases carry the caps
The point of an alias is that the caps live with the command instead of in whoever's memory. A per-alias block overrides the defaults, and a CLI flag overrides both.
defaults {
stall "30m" // hang backstop, not a runtime budget
max-parallel 2
retain "24h"
}
alias "test" {
command "npm"
args "run" "test"
max-time "15m"
}
alias "e2e" {
command "pytest"
args "tests/e2e" "--tb=short"
max-time "30m"
max-mem 4096
max-parallel 1 // binds a port; two copies fight
}Tell the model, in AGENTS.md
Shims and hooks catch the mechanical cases. The remaining gap is the model deciding to do something clever — running the suite through a subshell, or with an inline environment assignment, both of which tman deliberately refuses to rewrite because prefixing a string it did not parse changes what runs. A standing instruction in AGENTS.md closes that gap:
## Running tests and builds
Run every test, build, lint, and typecheck command through tman — never bare.
Prefer the repo-root shims (`./test`, `./lint`) when they exist; they carry
this project's `.tman.kdl` caps. Otherwise prefix explicitly:
tman run -- <command>
Never widen the caps from the command line. Exit 124 is a timeout, 125 a stall,
126 a resource cull — report those, do not retry with looser limits.AGENTS.md is read by Aider, Amp, Copilot CLI, Codex, Antigravity, and most things shipped since — and Copilot CLI and Antigravity additionally read CLAUDE.md and GEMINI.md. One file at the repository root usually covers your whole fleet.
If your agent gains a hook later
Check whether its pre-tool event can replace the command or only allow and deny it. If it replaces, point it straight at tman hook pretooluse and see whether the field names line up — the Codex and Gemini CLI guides cover both outcomes. If it only gates, the adapter in the Cursor guide is the pattern.
Verify it is actually on
A supervision integration that silently does nothing is worse than none, because it stops you looking. Two checks, both of which fail visibly:
# 1. the classifier agrees this command is worth supervising
echo '{"tool_name":"Bash","cwd":"'"$PWD"'","tool_input":{"command":"npm test"}}' \
| tman hook pretooluse
# 2. a real run shows up while it is in flight
tman run --name smoke -- sleep 30 &
tman listThe first prints a JSON object naming the rewritten command. Empty output means tman decided to stay out of the way — no .tman.kdl above cwd, a command it does not classify as test or build work, or a shell string it refused to parse. The second must list the run; if tman list is empty, nothing is being supervised.
Caps worth setting for agent-driven work
An agent re-runs the same command far more often than a human does, and it does it while you are not watching. That changes which caps earn their keep:
| cap | why it matters more under an agent |
|---|---|
--name | The agent will start the suite again before the last one finished. A dedup lock refuses the duplicate instead of running two copies against the same port or database. |
--max-parallel 2 | The default, and the right one for most repos. Excess runs queue on a slot file rather than stampeding your cores. |
--max-time | The only cap that bounds a run which is genuinely working but will never finish — a wait on a peer that never answers looks identical to healthy IO. |
--stall 30m | The built-in. A hang backstop, not a runtime budget: it should sit well above the longest quiet stretch your slowest command legitimately has. |
--max-mem | Opt-in, and worth it where a leak mode exists — worker pools, browser fleets, long-lived daemons. Off by default because builds are supposed to be greedy. |
Per-command starting points live in the tuning guides — one page per test and lint tool, with the reasoning behind each number rather than just the number.
Frequently asked
Does tman work with an agent that has no hook system?
Yes, and this is the primary mechanism rather than a fallback. `tman init --shims` writes supervised entry points at the repository root that any shell lookup resolves, so anything that shells out — an agent, a Makefile, a CI step, or you — runs supervised without the agent knowing tman exists.
Why does `./test` fail from my CI step when it works in a terminal?
A relative argv[0] is resolved through PATH, not the working directory. A workflow step or a language-level exec that is handed `./test` directly will look for it on PATH and often find an unrelated program of the same name. Write `sh -c "exec ./test"` so a shell does the resolution.
Can one AGENTS.md cover several different agents?
Usually. AGENTS.md is read by Aider, Amp, Codex, Copilot CLI, and Antigravity among others, and several of those also read CLAUDE.md and GEMINI.md — so a single file at the repository root, or one file plus symlinks, generally covers a mixed fleet.
Other agents
Sources
Vendor documentation this guide is written against — hook surfaces move, so check yours if something below does not match what you see.