AGENTS.md@public/files/gitbutler/crates/but · git:20260915.997c05b · 2026-09-15 · sha256 8f211c0600e8dc7f
AGENTS.md@public/files/gitbutler/crates/but git:20260915.997c05bA
Immutable. This exact content never changes and is served at /api/v1/blob/8f211c0600e8dc7f.
# but CLI Instructions
These supplement `crates/AGENTS.md` for work under `crates/but/`.
For CLI work that touches graph/workspace/branch/stack/commit relationships,
reachability, ordering, operation targets, or Git graph/history/ref-placement
changes, also read `crates/WORKSPACE_MODEL.md`.
## Command structure and I/O
- Use the `cli-commands` skill for guidance on how to write new CLI commands.
- Some commands define `ERROR_EXAMPLES` in `crates/but/src/args/` that are
shown on parse errors; keep them accurate when changing a command's
arguments or behavior.
## Worktree Guards And Deadlocks
Command handlers should acquire the required worktree guard at the top of the
operation and pass the derived permission down the call chain. Prefer
permission-taking helpers such as `*_with_perm(...)` when a guard is already
held. Do not call helpers that acquire another shared or exclusive worktree
guard while the command is still holding one.
When debugging a suspected worktree-lock deadlock, use a debug build with
`BUT_WS_LOCK_DEBUG=1`. In debug builds, this makes worktree guard acquisition
panic when the lock is already held instead of blocking indefinitely. Run the
failing command with a backtrace, for example:
```sh
BUT_WS_LOCK_DEBUG=1 RUST_BACKTRACE=1 cargo run -p but -- -C <repo> <command>
```
Use the panic backtrace to find the nested guard acquisition, then thread the
existing permission to that call site or switch it to an existing
permission-taking helper.
## CLI Tests
- In `crates/but/tests/`, prefer `env.but(...).assert().success()/failure()`
with `.stdout_eq(snapbox::str![...])` and
`.stderr_eq(snapbox::str![...])`; use `[..]` or `...` wildcards for unstable
portions instead of weakening the assertion.
- Update CLI snapshots with `SNAPSHOTS=overwrite cargo test -p but`,
scoped to a test name when possible. For colored terminal output, assert
against `snapbox::file!["snapshots/<test-name>/<invocation>.stdout.term.svg"]`
and update with the same command.
- When updating snapshots, always inspect the results to ensure that the
tests still test what they claim to
- Use sandbox helpers instead of `std::process::Command::new("git")`:
`env.invoke_bash(...)` for multi-line command sequences and
`env.invoke_git("...")` for single Git commands. Do not rewrite existing
`env.invoke_bash(...)` calls just to use `env.invoke_git(...)`.
- Avoid `env.but(...).output()` followed by direct stdout/stderr assertions;
keep output checks in snapbox. In tests, use panicking assertions such as
`assert!`, `assert_eq!`, or `assert_ne!` rather than `anyhow::ensure!`.
## CLI Skills
- After changing CLI commands or workflows, update `crates/but/skill/` so
bundled agent skills stay current.