harness-base: cargo --message-format short by default (#777)

closes #777. saves tokens by collapsing per-crate progress lines into
warning/error summaries when claude (or the operator) runs cargo
inside an agent container.

implementation: /etc/hyperhive/bash-cargo-short.sh defines a 'cargo'
bash function that injects '--message-format short' on compile
subcommands (build/check/clippy/test/run/doc/bench/install/rustc/fix).
loaded via BASH_ENV in non-interactive shells (claude's Bash tool
runs 'bash -c') and via programs.bash.interactiveShellInit in
interactive shells (operator SSH inside the container).

handles the '+toolchain' selector (cargo +nightly build), skips
injection when the caller already passes --message-format (any
form), leaves third-party cargo-* subcommands alone.

new option: hyperhive.cargo.shortMessages (default true) — agents
that parse cargo json output should set false.
This commit is contained in:
damocles 2026-05-31 14:28:05 +02:00 committed by mara
commit 5f61528133

View file

@ -537,6 +537,40 @@ in
'';
};
options.hyperhive.cargo.shortMessages = lib.mkOption {
type = lib.types.bool;
default = true;
example = false;
description = ''
Auto-inject `--message-format short` on cargo compile
subcommands (`build`, `check`, `clippy`, `test`, `run`,
`doc`, `bench`, `install`, `rustc`, `fix`) when claude (or
anything else) invokes `cargo` inside this container.
Saves tokens + context the verbose default output floods
the response window with per-crate progress lines that
carry no signal beyond the warning/error summary (#777).
Implementation: a `cargo` shell function defined in
`/etc/hyperhive/bash-cargo-short.sh`. Loaded via `BASH_ENV`
for non-interactive shells (`bash -c` what the claude
`Bash` tool runs) and sourced from `programs.bash.interactiveShellInit`
for interactive shells (operator pokes around inside the
container). The function:
- handles the `+toolchain` selector prefix (`cargo +nightly
build` works);
- passes through cleanly when the caller already specified
`--message-format` (any form);
- leaves non-compile subcommands (`new`, `add`, `search`,
third-party `cargo-*` subcommands) untouched so they
don't error on the unknown flag.
Set to `false` for agents that need full cargo output (e.g.
tooling that parses `--message-format json` programmatically
and doesn't pass the flag explicitly).
'';
};
options.hyperhive.autoCompact = lib.mkOption {
type = lib.types.bool;
default = true;
@ -712,6 +746,51 @@ in
source = config.hyperhive.icon;
};
# Cargo `--message-format short` injector (#777). Sourced from
# BASH_ENV in non-interactive shells AND interactiveShellInit
# so both claude's `Bash` tool and operator SSH sessions get
# the same compact compile output. `command cargo …` falls back
# to the un-wrapped binary in PATH (the rust toolchain's cargo
# — either from `environment.systemPackages` or from whatever
# `nix develop` shell the agent's working in).
environment.etc."hyperhive/bash-cargo-short.sh" =
lib.mkIf config.hyperhive.cargo.shortMessages
{
text = ''
# Auto-injects --message-format short on cargo compile
# subcommands so per-crate progress lines don't flood
# claude's context (#777). Bypassed when the caller
# already passes --message-format (any form).
cargo() {
# Strip leading +toolchain selectors (cargo +nightly …).
local pre=()
while [ "''${1:0:1}" = "+" ] && [ -n "''${1:-}" ]; do
pre+=("$1")
shift
done
case "''${1:-}" in
build|check|clippy|test|run|doc|bench|install|rustc|fix)
local sub="$1"
shift
local arg
for arg in "$@"; do
case "$arg" in
--message-format|--message-format=*)
command cargo "''${pre[@]}" "$sub" "$@"
return $?
;;
esac
done
command cargo "''${pre[@]}" "$sub" --message-format short "$@"
;;
*)
command cargo "''${pre[@]}" "$@"
;;
esac
}
'';
};
environment.etc."hyperhive/bash-allow.json".text =
builtins.toJSON config.hyperhive.allowedBashPatterns;
@ -773,8 +852,27 @@ in
}
// lib.optionalAttrs (config.hyperhive.forge.skipNotifyReasons != [ ]) {
HIVE_FORGE_NOTIFY_SKIP_REASONS = lib.concatStringsSep "," config.hyperhive.forge.skipNotifyReasons;
}
// lib.optionalAttrs config.hyperhive.cargo.shortMessages {
# Non-interactive bash invocations (claude's `Bash` tool runs
# `bash -c`) source $BASH_ENV at startup — drops the cargo
# function defined in the file above into scope without
# touching /etc/profile (login-only). Interactive shells
# source the same file via the interactiveShellInit hook
# below so behaviour matches across both modes (#777).
BASH_ENV = "/etc/hyperhive/bash-cargo-short.sh";
};
# Interactive shells don't honour BASH_ENV — wire the same file
# in via the bashrc hook so operator SSH sessions get the same
# short-format cargo output as claude's non-interactive calls.
programs.bash.interactiveShellInit =
lib.mkIf config.hyperhive.cargo.shortMessages ''
if [ -r /etc/hyperhive/bash-cargo-short.sh ]; then
. /etc/hyperhive/bash-cargo-short.sh
fi
'';
boot.isNspawnContainer = true;
# Every agent gets flakes + the modern `nix` CLI out of the box.