mm scripts: default to MiniMax-M3.1-Flash-Preview with per-script effort

Flash is the default model; --m3 falls back to M3, --effort overrides.
Defaults: max (review-minimax, review-loop, mm-worktree-task), medium
(explore), low (ci-triage). ask-minimax-run applies MINIMAX_EFFORT to
Flash models when --effort is not passed. Bump stale fixture date.
This commit is contained in:
Paul O'Reilly
2026-10-13 10:23:53 +13:00
parent d6e0220bf5
commit 840d7509e1
16 changed files with 134 additions and 30 deletions

View File

@@ -26,4 +26,15 @@ export CLAUDE_CONFIG_DIR="$MINIMAX_DIR"
export CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1
export COLORTERM=truecolor
# MINIMAX_EFFORT (provider.env) applies to Flash models only, unless the caller passed --effort.
model="${ANTHROPIC_MODEL:-}"; has_effort=0; prev=""
for a in "$@"; do
[[ "$prev" == "--model" ]] && model="$a"
[[ "$a" == "--effort" ]] && has_effort=1
prev="$a"
done
if [[ -n "${MINIMAX_EFFORT:-}" && $has_effort -eq 0 && "$model" == *Flash* ]]; then
set -- --effort "$MINIMAX_EFFORT" "$@"
fi
exec claude "$@"

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Triage a failing Gitea Actions run in a MiniMax M3 sub-session.
# Triage a failing Gitea Actions run in a MiniMax sub-session.
# Fetches logs via gitea-agent-companion (token stays inside gac), redacts
# credential-shaped content, and has MiniMax write a structured triage file.
# Spec: specs/ci-triage-minimax-run.spec.md. Used by /ci-triage-minimax.
@@ -7,7 +7,7 @@
# Usage:
# ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>]
# [--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS]
# [--dryrun|-n]
# [--dryrun|-n] [--m3] [--effort low|medium|high|xhigh|max]
#
# Exit codes:
# 0 triage file written
@@ -25,6 +25,8 @@ OUT_FILE=""
TAIL_LINES=2000
MAX_TURNS=25
TIMEOUT_SECS=300
USE_M3=0
EFFORT_ARG=""
DRYRUN=0
CRED_PATTERN='ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}'
@@ -37,11 +39,15 @@ while [[ $# -gt 0 ]]; do
--tail) TAIL_LINES="$2"; shift 2 ;;
--max-turns) MAX_TURNS="$2"; shift 2 ;;
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
--m3) USE_M3=1; shift ;;
--effort) EFFORT_ARG="$2"; shift 2 ;;
--dryrun|-n) DRYRUN=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
esac
done
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-low}"; fi
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
# --- CT-1 preflight -----------------------------------------------------------
[[ "$REPO" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]] || { echo "error: --repo must be owner/repo" >&2; exit 1; }
@@ -82,7 +88,7 @@ if [[ "$DRYRUN" -eq 1 ]]; then
echo "-- failing step --"
echo "<run-logs not fetched in dryrun>"
echo "-- sub-session command --"
echo "cd <workdir> && timeout $TIMEOUT_SECS ask-minimax-run --model 'MiniMax-M3[1m]'" \
echo "cd <workdir> && timeout $TIMEOUT_SECS ask-minimax-run --model '$MODEL'${EFFORT:+ --effort $EFFORT}" \
"--permission-mode default --allowedTools 'Read,Glob,Grep,Write'" \
"--disallowedTools 'Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch'" \
"--max-turns $MAX_TURNS --output-format json --add-dir $OUT_DIR -p < prompt.txt"
@@ -163,7 +169,7 @@ run_once() {
return 0
fi
( cd "$WORK_DIR" && timeout "$TIMEOUT_SECS" ask-minimax-run \
--model "MiniMax-M3[1m]" \
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
--permission-mode default \
--allowedTools "Read,Glob,Grep,Write" \
--disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Run a read-only codebase exploration sweep in a MiniMax M3 sub-session.
# Run a read-only codebase exploration sweep in a MiniMax sub-session.
# Wraps ask-minimax-run with the hardening the exploration case needs:
# - --add-dir per search root (paths outside cwd are otherwise denied)
# - secrets-root refusal + skip-list in the prompt preamble
@@ -11,7 +11,8 @@
# Usage:
# explore-minimax-run --root <path> [--root <path> ...] \
# --prompt-file <question-file> --out <result-file> \
# [--breadth medium|very-thorough] [--max-turns N] [--timeout SECS]
# [--breadth medium|very-thorough] [--max-turns N] [--timeout SECS] \
# [--m3] [--effort low|medium|high|xhigh|max]
#
# Exit codes:
# 0 answer written to --out
@@ -20,7 +21,7 @@
# 3 ran but answer is empty or carries no file:line citations — fall back to an Explore agent
set -euo pipefail
usage() { grep '^#' "$0" | sed 's/^# \{0,1\}//' | sed -n '2,20p'; }
usage() { grep '^#' "$0" | sed 's/^# \{0,1\}//' | sed -n '2,21p'; }
ROOTS=()
PROMPT_FILE=""
@@ -28,6 +29,8 @@ OUT_FILE=""
BREADTH="medium"
MAX_TURNS=40
TIMEOUT_SECS=540
USE_M3=0
EFFORT_ARG=""
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -37,10 +40,14 @@ while [[ $# -gt 0 ]]; do
--breadth) BREADTH="$2"; shift 2 ;;
--max-turns) MAX_TURNS="$2"; shift 2 ;;
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
--m3) USE_M3=1; shift ;;
--effort) EFFORT_ARG="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
esac
done
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-medium}"; fi
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
[[ ${#ROOTS[@]} -gt 0 ]] || { echo "error: at least one --root required" >&2; exit 1; }
[[ -n "$PROMPT_FILE" && -f "$PROMPT_FILE" ]] || { echo "error: --prompt-file missing or not a file" >&2; exit 1; }
@@ -109,7 +116,7 @@ run_once() {
# --disallowedTools: the minimax profile defaults to acceptEdits and allows
# Edit(/tmp/**)/WebFetch at user level; deny beats allow.
timeout "$TIMEOUT_SECS" ask-minimax-run \
--model MiniMax-M3 \
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
--permission-mode default \
--allowedTools "Read,Glob,Grep" \
--disallowedTools "Write,Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Launch a MiniMax M3 implementation sub-session in an isolated git worktree,
# Launch a MiniMax implementation sub-session in an isolated git worktree,
# with the prompt assembled from a planner work item. See specs/mm-worktree-task.spec.md.
set -euo pipefail
@@ -15,7 +15,7 @@ usage() {
cat <<'EOF'
Usage: mm-worktree-task <item-uuid> [OPTIONS]
Launch a MiniMax M3 implementation sub-session (via ask-minimax-run) in an
Launch a MiniMax implementation sub-session (via ask-minimax-run) in an
isolated git worktree of the current repo, with the prompt assembled from a
planner work item.
@@ -33,6 +33,9 @@ Options:
--docs all|recent|none Which item documents to bundle (default: recent)
--tools "<list>" Extra --allowedTools entries (comma-separated)
--timeout <secs> Sub-session timeout (default: 1800)
--m3 Use MiniMax-M3[1m] instead of the default MiniMax-M3.1-Flash-Preview
--effort <level> Thinking depth low|medium|high|xhigh|max (default: max;
not sent with --m3 unless given)
--gate "<command>" Re-run this command in the worktree yourself, after
the sub-session exits, against its LAST commit.
Appended as a "Supervisor gate" section in the
@@ -68,6 +71,8 @@ BASE="main"
DOCS="recent"
EXTRA_TOOLS=""
TIMEOUT=1800
USE_M3=0
EFFORT_ARG=""
GATE=""
GATE_TIMEOUT=900
UPLOAD=0
@@ -87,6 +92,8 @@ while [[ $# -gt 0 ]]; do
--gate) GATE="$2"; shift 2 ;;
--gate-timeout) GATE_TIMEOUT="$2"; shift 2 ;;
--context) CP_CONTEXT="$2"; shift 2 ;;
--m3) USE_M3=1; shift ;;
--effort) EFFORT_ARG="$2"; shift 2 ;;
--upload) UPLOAD=1; shift ;;
--collect) COLLECT=1; shift ;;
--dryrun|-n) DRYRUN=1; shift ;;
@@ -98,6 +105,9 @@ while [[ $# -gt 0 ]]; do
esac
done
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-max}"; fi
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { err "--effort must be low|medium|high|xhigh|max"; exit 1; }
case "$DOCS" in all|recent|none) ;; *) err "--docs must be all|recent|none"; exit 1 ;; esac
if [[ -z "$UUID" ]]; then
@@ -374,7 +384,7 @@ EOF
PROMPT_CONTENT="$(build_prompt)"
CMD="cd ${WORKTREE} && setsid nohup timeout ${TIMEOUT} ask-minimax-run --model \"MiniMax-M3[1m]\" --allowedTools \"${ALLOWLIST}\" --permission-mode acceptEdits --add-dir ${REPORT_DIR} -p \"\$(cat ${PROMPT_FILE})\" > ${STDOUT_FILE} 2>&1"
CMD="cd ${WORKTREE} && setsid nohup timeout ${TIMEOUT} ask-minimax-run --model \"${MODEL}\"${EFFORT:+ --effort ${EFFORT}} --allowedTools \"${ALLOWLIST}\" --permission-mode acceptEdits --add-dir ${REPORT_DIR} -p \"\$(cat ${PROMPT_FILE})\" > ${STDOUT_FILE} 2>&1"
if [[ $DRYRUN -eq 1 ]]; then
echo "[dryrun] mm-worktree-task — no changes will be made"
@@ -510,7 +520,7 @@ info "launching ask-minimax-run (detached, timeout ${TIMEOUT}s)"
cd "$WORKTREE"
start=$(date +%s)
set +e
setsid nohup timeout "$TIMEOUT" ask-minimax-run --model "MiniMax-M3[1m]" \
setsid nohup timeout "$TIMEOUT" ask-minimax-run --model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
--allowedTools "$ALLOWLIST" --permission-mode acceptEdits \
--add-dir "$REPORT_DIR" -p "$(cat "$PROMPT_FILE")" \
> "$STDOUT_FILE" 2>&1

View File

@@ -17,6 +17,7 @@ Usage:
review-loop-run launch --kind <plan|spec|tests|code|verify> --name <tag> [--round N]
--file <path> [--file <path> ...] [--context "<text>"]
[--prev <result.md>] [--tools "<extra>"] [--timeout <secs>]
[--m3] [--effort low|medium|high|xhigh|max]
[--project <repo>] [--dryrun|-n]
review-loop-run status [--name <tag>] [--round N] [--project <repo>]
review-loop-run counts <result.md>
@@ -238,7 +239,7 @@ kind_tools() {
}
cmd_launch() {
local kind="" name="" round=1 context="" prev="" tools="" timeout=1500 project="" dryrun=0
local kind="" name="" round=1 context="" prev="" tools="" timeout=1500 project="" dryrun=0 use_m3=0 effort_arg=""
local -a files=()
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -251,11 +252,15 @@ cmd_launch() {
--tools) tools="$2"; shift 2 ;;
--timeout) timeout="$2"; shift 2 ;;
--project) project="$2"; shift 2 ;;
--m3) use_m3=1; shift ;;
--effort) effort_arg="$2"; shift 2 ;;
--dryrun|-n) dryrun=1; shift ;;
-h|--help) usage; exit 0 ;;
*) die "unknown option: $1" 2 ;;
esac
done
if [[ $use_m3 -eq 1 ]]; then model="MiniMax-M3"; effort="$effort_arg"; else model="MiniMax-M3.1-Flash-Preview"; effort="${effort_arg:-max}"; fi
[[ -z "$effort" || "$effort" =~ ^(low|medium|high|xhigh|max)$ ]] || die "--effort must be low|medium|high|xhigh|max" 2
[[ " $KINDS " == *" $kind "* ]] || die "--kind must be one of: $KINDS" 2
[[ "$name" =~ ^[A-Za-z0-9._-]+$ ]] || die "--name must match ^[A-Za-z0-9._-]+\$" 2
[[ "$round" =~ ^[0-9]+$ ]] || die "--round must be an integer" 2
@@ -323,7 +328,7 @@ EOF
launch_body=$(cat <<EOF
#!/usr/bin/env bash
cd "$repo" || exit 1
timeout ${timeout} ask-minimax-run --model MiniMax-M3 --allowedTools "$allow" --permission-mode acceptEdits -p "\$(cat "$prompt")" > "$stdout" 2>&1
timeout ${timeout} ask-minimax-run --model ${model}${effort:+ --effort ${effort}} --allowedTools "$allow" --permission-mode acceptEdits -p "\$(cat "$prompt")" > "$stdout" 2>&1
echo "exit=\$?" >> "$stdout"
EOF
)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# First-pass code review of a git branch in a MiniMax M3 sub-session.
# First-pass code review of a git branch in a MiniMax sub-session.
# The wrapper materialises the diff/log itself (the sub-session gets no Bash),
# runs MiniMax read-only except for one findings file, and gates the result.
# Spec: specs/review-minimax-run.spec.md. Used by /review-minimax; safe directly.
@@ -7,7 +7,7 @@
# Usage:
# review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>]
# [--profile agent-runtimes] [--max-diff-lines N] [--max-turns N]
# [--timeout SECS] [--dryrun|-n]
# [--timeout SECS] [--dryrun|-n] [--m3] [--effort low|medium|high|xhigh|max]
#
# Exit codes:
# 0 findings file written (may contain "NO FINDINGS")
@@ -25,6 +25,8 @@ PROFILE=""
MAX_DIFF_LINES=6000
MAX_TURNS=40
TIMEOUT_SECS=540
USE_M3=0
EFFORT_ARG=""
DRYRUN=0
# RM-3: credential-shaped content in the diff aborts the review outright.
CRED_PATTERN='ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}'
@@ -38,11 +40,15 @@ while [[ $# -gt 0 ]]; do
--max-diff-lines) MAX_DIFF_LINES="$2"; shift 2 ;;
--max-turns) MAX_TURNS="$2"; shift 2 ;;
--timeout) TIMEOUT_SECS="$2"; shift 2 ;;
--m3) USE_M3=1; shift ;;
--effort) EFFORT_ARG="$2"; shift 2 ;;
--dryrun|-n) DRYRUN=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "error: unknown argument '$1'" >&2; usage >&2; exit 1 ;;
esac
done
if [[ $USE_M3 -eq 1 ]]; then MODEL="MiniMax-M3[1m]"; EFFORT="$EFFORT_ARG"; else MODEL="MiniMax-M3.1-Flash-Preview"; EFFORT="${EFFORT_ARG:-max}"; fi
[[ -z "$EFFORT" || "$EFFORT" =~ ^(low|medium|high|xhigh|max)$ ]] || { echo "error: --effort must be low|medium|high|xhigh|max" >&2; exit 1; }
# --- RM-1 preflight -----------------------------------------------------------
[[ -n "$WORKTREE" ]] || { echo "error: --worktree required" >&2; exit 1; }
@@ -172,7 +178,7 @@ if [[ "$DRYRUN" -eq 1 ]]; then
echo "-- prompt --"
cat "$FULL_PROMPT"
echo "-- command --"
echo "cd $WORK_DIR && timeout $TIMEOUT_SECS ask-minimax-run --model 'MiniMax-M3[1m]'" \
echo "cd $WORK_DIR && timeout $TIMEOUT_SECS ask-minimax-run --model '$MODEL'${EFFORT:+ --effort $EFFORT}" \
"--permission-mode default --allowedTools 'Read,Glob,Grep,Write'" \
"--disallowedTools 'Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch'" \
"--max-turns $MAX_TURNS --output-format json --add-dir $WORKTREE --add-dir $OUT_DIR -p < prompt.txt"
@@ -189,7 +195,7 @@ run_once() {
return 0
fi
( cd "$WORK_DIR" && timeout "$TIMEOUT_SECS" ask-minimax-run \
--model "MiniMax-M3[1m]" \
--model "$MODEL" ${EFFORT:+--effort "$EFFORT"} \
--permission-mode default \
--allowedTools "Read,Glob,Grep,Write" \
--disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" \

View File

@@ -8,7 +8,7 @@ Triage a failing Gitea Actions run in a MiniMax M3 sub-session: fetch the run's
```
ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
[--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS] [--dryrun|-n]
[--out <triage-file>] [--tail N] [--max-turns N] [--timeout SECS] [--dryrun|-n] [--m3] [--effort LEVEL]
```
| Flag | Default | Description |
@@ -20,6 +20,8 @@ ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
| `--tail` | 2000 | Log lines fetched (gac `--tail`) |
| `--max-turns` | 25 | Sub-session turn cap |
| `--timeout` | 300 | Internal timeout (logs-only task; well under the harness Bash 600s cap) |
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
| `--effort <level>` | `low` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
| `--dryrun`, `-n` | off | Print resolved config, the gac command, the full prompt, and the sub-session command line; invoke neither gac's log fetch nor the sub-session |
## Requirements
@@ -30,7 +32,7 @@ ci-triage-minimax-run --repo <owner/repo> --run <N> [--job <name|id>] \
- **CT-4 Redaction.** Before prompt assembly, credential-shaped content in `run-logs.ndjson` (`ghp_…|glpat-|x-access-token:|Authorization:|BEGIN … PRIVATE KEY|AKIA…` — same pattern set as review-minimax-run) is replaced in place with `[REDACTED]`. Redact-and-continue, not abort: CI logs routinely carry unmasked clone URLs and the log is the whole payload. Residual risk: best-effort patterns; novel credential formats can pass.
- **CT-5 Envelope parse.** `failed_step`, `sliced`, and `note` are extracted from the NDJSON envelope with jq. If `failed_step` is null (cancelled/crashed run, green multi-job), the prompt states this and the output contract requires the literal `UNKNOWN` under `## Failing step` — no fabricated step names.
- **CT-6 Prompt contract.** Fixed preamble: read-only triage of the two files in cwd; explicit error-signature patterns to search (`error:|FAILED|Traceback|exit code|denied|timeout|not found|no such|ECONN|refused`); do not suggest running tests or builds; if the log carries the truncation marker or `sliced` is partial, say so — do not improvise. Output sections, exactly: `## Failing step` / `## Error excerpt` (≤10 verbatim lines) / `## Probable cause` (1–3 sentences, non-empty) / `## Suggested next action` (one command or one edit description — advisory only) / `## Confidence`.
- **CT-7 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <out-dir> -p`. Same rationale set as review-minimax-run RM-6; no worktree access needed.
- **CT-7 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <out-dir> -p`. Same rationale set as review-minimax-run RM-6; no worktree access needed.
- **CT-8 Result gate.** Triage file exists, contains `## Failing step`, and has a non-blank line under `## Probable cause`.
- **CT-9 Retry.** On MiniMax error or gate failure: remove the out-file, retry once; never retry timeout (rc 124); then exit 2 (transport) or 3 (gate). The gac fetch is NOT retried by the script (single fetch, reused across both attempts).
- **CT-10 Test seams.** `CI_TRIAGE_FAKE_LOGS=<file>` bypasses the gac fetch (file used as `run-logs.ndjson`; `jobs.txt` gets a placeholder); `CI_TRIAGE_FAKE_JSON=<file>` substitutes the sub-session envelope; `CI_TRIAGE_FAKE_TRIAGE=<file>` (companion, optional) plays the sub-session's Write of the triage file. Gates and retry logic still run, so exits 0/2/3 and the redaction step are assertable offline.

View File

@@ -9,7 +9,7 @@ Run a broad, read-only "where does X live" codebase exploration in a MiniMax M3
```
explore-minimax-run --root <path> [--root <path> ...] \
--prompt-file <question-file> --out <result-file> \
[--breadth medium|very-thorough] [--max-turns N] [--timeout SECS]
[--breadth medium|very-thorough] [--max-turns N] [--timeout SECS] [--m3] [--effort LEVEL]
```
| Flag | Default | Description |
@@ -20,6 +20,8 @@ explore-minimax-run --root <path> [--root <path> ...] \
| `--breadth` | `medium` | `medium` (stop when confidently answered) or `very-thorough` (full sweep, alternate naming conventions) |
| `--max-turns` | 40 | Sub-session turn cap |
| `--timeout` | 540 | Internal timeout in seconds (keeps callers under the harness Bash 600s cap) |
| `--m3` | off | Use `MiniMax-M3` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
| `--effort <level>` | `medium` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
## Behaviour / requirements

View File

@@ -26,6 +26,8 @@ mm-worktree-task <item-uuid> [OPTIONS]
| `--docs all\|recent\|none` | `recent` | Which item documents to bundle. `recent` = documents updated in the last 14 days; falls back to `all` if the CLI does not expose update dates. The full list of document names is always included in the prompt regardless of which are bundled. |
| `--tools "<list>"` | — | Extra `--allowedTools` entries merged into the default allowlist (comma-separated). |
| `--timeout <secs>` | `1800` | Max seconds the sub-session may run (`timeout <secs>` wrapper). |
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
| `--gate "<command>"` | — | Supervisor gate: after the sub-session exits, `mm-worktree-task` itself re-runs this command in the worktree against the sub-session's LAST commit and appends a `## Supervisor gate` section to the result file (see Behaviour §8). Never trust the agent's own "tests pass" claim — this re-run is the check. |
| `--gate-timeout <secs>` | `900` | Max seconds `--gate`'s command may run before it is killed and recorded as a timed-out (failed) gate. |
| `--context <name>` | resolved (see §0) | `cp-cli --context` used for every planner call. |
@@ -76,7 +78,7 @@ mm-worktree-task <item-uuid> [OPTIONS]
- If `--brief <file>` is given, its content is appended (or used standalone as the task body when no uuid was given).
8. Launch detached (skipped under `--dryrun` and `--collect`):
```
cd <worktree> && setsid nohup timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" \
cd <worktree> && setsid nohup timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" \
--allowedTools "<default-allowlist>[,<--tools>]" --permission-mode acceptEdits \
--add-dir <report-dir> -p "$(cat <prompt-file>)" \
> <report-dir>/<slug>-stdout.txt 2>&1

View File

@@ -9,7 +9,7 @@ Launch a detached MiniMax M3 review of a review-loop artefact (plan, spec diff,
```
review-loop-run launch --kind <plan|spec|tests|code|verify> --name <tag> [--round N] \
--file <path> [--file <path> ...] [--context "<text>"] [--prev <result.md>] \
[--tools "<extra allowedTools>"] [--timeout <secs>] [--dryrun|-n]
[--tools "<extra allowedTools>"] [--timeout <secs>] [--m3] [--effort <level>] [--dryrun|-n]
review-loop-run status [--name <tag>] [--round N]
review-loop-run counts <result.md>
review-loop-run --help
@@ -35,6 +35,8 @@ review-loop-run --help
| `--prev` | auto | Explicit previous-round result file (overrides the auto lookup). |
| `--tools` | kind default | Extra `--allowedTools` entries (comma-separated). |
| `--timeout` | 1500 | Seconds before the sub-session is killed. |
| `--m3` | off | Use `MiniMax-M3` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
| `--project` | current repo root | Repo to `cd` into before launching. |
| `--dryrun`, `-n` | off | Print the assembled prompt and the exact launch command; write nothing; launch nothing. |
@@ -51,7 +53,7 @@ review-loop-run --help
2. Validate: kind in the closed set, name matches `^[A-Za-z0-9._-]+$`, every `--file` exists, `ask-minimax-run` on PATH, MiniMax profile present.
3. Assemble the prompt from the kind template (§Templates): header (non-interactive, write to the output file), task text, `--context`, the "Files to read" list = `--file` entries + the kind's default best-practices/gotcha files that exist + the previous-round result (rounds ≥2), the output path, constraints.
4. Write `<dir>/<name>-r<N>-prompt.txt`.
5. Write `<dir>/<name>-r<N>-launch.sh` (a tiny bash script that `cd`s to the repo, runs `timeout <secs> ask-minimax-run --model MiniMax-M3 --allowedTools "<list>" --permission-mode acceptEdits -p "$(cat prompt)" > stdout 2>&1`, then appends `exit=$?` to the stdout file) and starts it with `setsid nohup <launch.sh> >/dev/null 2>&1 &`.
5. Write `<dir>/<name>-r<N>-launch.sh` (a tiny bash script that `cd`s to the repo, runs `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --allowedTools "<list>" --permission-mode acceptEdits -p "$(cat prompt)" > stdout 2>&1`, then appends `exit=$?` to the stdout file) and starts it with `setsid nohup <launch.sh> >/dev/null 2>&1 &`.
6. Print the three paths and `launched`.
`status` scans `<dir>/*-r*-stdout.txt`; a file whose last line matches `^exit=` is `done`, else `running`; counts come from `counts`.

View File

@@ -9,7 +9,7 @@ Run a first-pass code review of a git branch (typically an agent-produced worktr
```
review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
[--profile agent-runtimes] [--max-diff-lines N] [--max-turns N] \
[--timeout SECS] [--dryrun|-n]
[--timeout SECS] [--dryrun|-n] [--m3] [--effort LEVEL]
```
| Flag | Default | Description |
@@ -21,6 +21,8 @@ review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
| `--max-diff-lines` | 6000 | Diff budget; larger diffs exit 1 with the count |
| `--max-turns` | 40 | Sub-session turn cap |
| `--timeout` | 540 | Internal timeout (keeps callers under the harness Bash 600s cap). Why: a longer run invoked synchronously from a skill is killed by the harness with no findings file. |
| `--m3` | off | Use `MiniMax-M3[1m]` instead of the default `MiniMax-M3.1-Flash-Preview` (1M window natively, always thinks). No effort is sent unless `--effort` is given. |
| `--effort <level>` | `max` | Thinking depth `low\|medium\|high\|xhigh\|max`, passed to `ask-minimax-run --effort`. Any other value exits 1. |
| `--dryrun`, `-n` | off | Print resolved config, materialised-input plan, full prompt, and the exact sub-session command line; create/invoke nothing beyond the scratch dir |
## Requirements
@@ -30,7 +32,7 @@ review-minimax-run --worktree <path> [--base <ref>] [--out <findings-file>] \
- **RM-3 Redaction gate.** If `diff.patch` matches `ghp_[A-Za-z0-9]|glpat-|x-access-token:|Authorization:|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}`, exit 1 with "diff contains credential-shaped content; review in-session". No redact-and-continue for diffs: a credential in a diff means the branch itself needs attention.
- **RM-4 Empty/oversize diff.** Empty `diff.patch` → exit 1 "nothing to review". More than `--max-diff-lines` lines → exit 1 with the count.
- **RM-5 Prompt contract.** Fixed preamble: first-pass reviewer, non-interactive; inputs are the three files in cwd; the worktree is readable for surrounding context only; write ONLY the findings file at the given path; never modify any other file; do not run anything, fix anything, or improvise if an input is missing/truncated — say so and stop. Checklist = unconditional core (distilled from llm-code-security §10/§12: injection, hardcoded credentials, unquoted shell vars, verify=False, weak hashing/random, missing input validation, chmod 777, curl|bash, unpinned images/deps, missing idempotency, unconditional health checks, missing locking) as explicit grep-able patterns; `--profile agent-runtimes` appends the 5 recurring MiniMax test-file bugs. Findings format: `### [BLOCKER|SHOULD-FIX|NIT] <title>` blocks with `file:line`, ≤10-line excerpt, category, `Confidence: confirmed|suspected`; clean review → literal `NO FINDINGS`.
- **RM-6 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "MiniMax-M3[1m]" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <worktree> --add-dir <out-dir> -p < prompt > response.json`. Why each: `[1m]` pins the 1M window (unknown model ids get 200k + early auto-compact); `Write` must be allowlisted or MiniMax exits 0 without creating the file; `default` not `acceptEdits` — new-file Write needs no edit approval and nothing else is auto-approved; deny-list beats the profile's permissive defaults.
- **RM-6 Invocation.** From the scratch dir: `timeout <secs> ask-minimax-run --model "$MODEL" --effort "$EFFORT" --permission-mode default --allowedTools "Read,Glob,Grep,Write" --disallowedTools "Edit,MultiEdit,NotebookEdit,Bash,WebFetch,WebSearch" --max-turns N --output-format json --add-dir <worktree> --add-dir <out-dir> -p < prompt > response.json`. Why each: `$MODEL` is Flash (1M natively) by default; with `--m3`, `[1m]` pins the 1M window (unknown model ids get 200k + early auto-compact); `Write` must be allowlisted or MiniMax exits 0 without creating the file; `default` not `acceptEdits` — new-file Write needs no edit approval and nothing else is auto-approved; deny-list beats the profile's permissive defaults.
- **RM-7 Clean-tree assertion.** After each attempt, `git -C <worktree> status --porcelain` must be empty; a dirtied tree is exit 2 (and the dirt is reported, not reverted).
- **RM-8 Result gate.** Findings file exists AND (contains `NO FINDINGS` OR (≥1 line matching `^### \[(BLOCKER|SHOULD-FIX|NIT)\]` AND ≥1 finding cites a path that exists relative to the worktree)). A bare `:NNN` match is NOT sufficient — timestamps and counters satisfy that.
- **RM-9 Retry.** On MiniMax error OR gate failure: remove the out-file and retry once (covers the "exit 0, file never written" failure and prevents a stale attempt-1 file passing the gate). Never retry a timeout (rc 124). Then exit 2 (transport/timeout/dirty-tree) or 3 (gate).

View File

@@ -1 +1 @@
{"documents": [{"name": "notes.md", "updated_at": "2026-09-01T00:00:00Z"}, {"name": "old-notes.md", "updated_at": "2020-01-01T00:00:00Z"}]}
{"documents": [{"name": "notes.md", "updated_at": "2026-10-10T00:00:00Z"}, {"name": "old-notes.md", "updated_at": "2020-01-01T00:00:00Z"}]}

View File

@@ -27,6 +27,16 @@ assert_contains() {
fi
}
assert_not_contains() {
local label=$1 needle=$2 haystack=$3
if [[ "$haystack" != *"$needle"* ]]; then
printf " ${GREEN}PASS${NC} %s\n" "$label"; PASS=$((PASS + 1))
else
printf " ${RED}FAIL${NC} %s\n" "$label"
printf " expected NOT to contain: %s\n" "$needle"; FAIL=$((FAIL + 1))
fi
}
assert_eq() {
local label=$1 expected=$2 actual=$3
if [[ "$expected" == "$actual" ]]; then
@@ -70,10 +80,20 @@ echo "== dryrun =="
DRY_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --dryrun 2>&1)"
assert_eq "dryrun exits 0" 0 $?
assert_contains "dryrun shows gac command" "inspect skynet/gac-scratch --run 42" "$DRY_OUT"
assert_contains "dryrun shows model pin" "MiniMax-M3[1m]" "$DRY_OUT"
assert_contains "dryrun defaults to Flash" "MiniMax-M3.1-Flash-Preview" "$DRY_OUT"
assert_contains "dryrun default effort low" "--effort low" "$DRY_OUT"
assert_contains "dryrun defers fetch" "not fetched in dryrun" "$DRY_OUT"
assert_contains "dryrun shows job passthrough default" "job: auto" "$DRY_OUT"
echo "== dryrun --m3/--effort =="
M3_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --m3 --dryrun 2>&1)"
assert_eq "m3 dryrun exits 0" 0 $?
assert_contains "m3 dryrun shows M3 model" "MiniMax-M3[1m]" "$M3_OUT"
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
EF_OUT="$("$SCRIPT" --repo skynet/gac-scratch --run 42 --effort high --dryrun 2>&1)"
assert_contains "explicit effort overrides default" "--effort high" "$EF_OUT"
"$SCRIPT" --repo o/r --run 1 --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" 1 $?
echo "== fake logs: redaction + failing step in prompt, exit 0 =="
OUT0="$TMP/out0.md"
RUN_OUT="$(CI_TRIAGE_FAKE_LOGS="$FAKE_LOGS" CI_TRIAGE_FAKE_JSON="$FAKE_OK_JSON" CI_TRIAGE_FAKE_TRIAGE="$FAKE_TRIAGE" \

View File

@@ -83,7 +83,15 @@ assert_contains "dryrun shows worktree path" ".claude/worktrees/mm-testslug" "$D
assert_contains "dryrun shows branch name" "mm/testslug" "$DRY_OUT"
assert_contains "dryrun shows bundle path" "testslug-bundle.md" "$DRY_OUT"
assert_contains "dryrun shows the ask-minimax-run command" "ask-minimax-run" "$DRY_OUT"
assert_contains "dryrun command uses MiniMax-M3[1m] model" 'MiniMax-M3[1m]' "$DRY_OUT"
assert_contains "dryrun command defaults to Flash model" 'MiniMax-M3.1-Flash-Preview' "$DRY_OUT"
assert_contains "dryrun default effort max" "--effort max" "$DRY_OUT"
M3_OUT="$("$SCRIPT" "$TEST_UUID" --slug testslug --m3 --dryrun 2>&1)"
assert_eq "m3 dryrun exits 0" "0" "$?"
assert_contains "m3 dryrun uses M3[1m] model" 'MiniMax-M3[1m]' "$M3_OUT"
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
EF_OUT="$("$SCRIPT" "$TEST_UUID" --slug testslug --effort low --dryrun 2>&1)"
assert_contains "explicit effort overrides default" "--effort low" "$EF_OUT"
"$SCRIPT" "$TEST_UUID" --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" "1" "$?"
assert_contains "dryrun bundles recent doc notes.md" "notes.md (bundled below)" "$DRY_OUT"
assert_contains "dryrun lists old doc as available only" "old-notes.md (available only)" "$DRY_OUT"
assert_not_contains "dryrun does not bundle stale doc body" "Stale notes, should not be bundled" "$DRY_OUT"

View File

@@ -19,6 +19,9 @@ assert_contains "dryrun banner" "[dryrun]" "$out"
assert_contains "nothing launched" "nothing launched" "$out"
assert_contains "task text is the spec template" "OUT OF SCOPE: reporting that a symbol" "$out"
assert_contains "context included" "Context: closes bug 1234" "$out"
assert_contains "defaults to Flash" "--model MiniMax-M3.1-Flash-Preview --effort max" "$out"
out_m3=$("$SCRIPT" launch --kind spec --name spec-Y --file "$TMP/spec.diff" --m3 -n 2>&1)
assert_contains "--m3 uses M3 with no effort" "--model MiniMax-M3 --allowedTools" "$out_m3"
assert_contains "output path uses tag" "spec-X-r1-result.md" "$out"
assert_contains "present default listed" "$TMP/bp/spec-driven-development.md" "$out"
assert_contains "absent default skipped" "default file absent, skipped" "$out"

View File

@@ -27,6 +27,16 @@ assert_contains() {
fi
}
assert_not_contains() {
local label=$1 needle=$2 haystack=$3
if [[ "$haystack" != *"$needle"* ]]; then
printf " ${GREEN}PASS${NC} %s\n" "$label"; PASS=$((PASS + 1))
else
printf " ${RED}FAIL${NC} %s\n" "$label"
printf " expected NOT to contain: %s\n" "$needle"; FAIL=$((FAIL + 1))
fi
}
assert_eq() {
local label=$1 expected=$2 actual=$3
if [[ "$expected" == "$actual" ]]; then
@@ -68,7 +78,15 @@ echo "== dryrun =="
DRY_OUT="$("$SCRIPT" --worktree "$REPO" --dryrun 2>&1)"
assert_eq "dryrun exits 0" 0 $?
assert_contains "dryrun shows branch" "branch: feature" "$DRY_OUT"
assert_contains "dryrun shows model pin" "MiniMax-M3[1m]" "$DRY_OUT"
assert_contains "dryrun defaults to Flash" "MiniMax-M3.1-Flash-Preview" "$DRY_OUT"
assert_contains "dryrun default effort max" "--effort max" "$DRY_OUT"
M3_OUT="$("$SCRIPT" --worktree "$REPO" --m3 --dryrun 2>&1)"
assert_eq "m3 dryrun exits 0" 0 $?
assert_contains "m3 dryrun shows M3 model" "MiniMax-M3[1m]" "$M3_OUT"
assert_not_contains "m3 dryrun sends no effort" "--effort" "$M3_OUT"
EF_OUT="$("$SCRIPT" --worktree "$REPO" --effort high --dryrun 2>&1)"
assert_contains "explicit effort overrides default" "--effort high" "$EF_OUT"
"$SCRIPT" --worktree "$REPO" --effort bogus --dryrun >/dev/null 2>&1; assert_eq "bad effort exits 1" 1 $?
assert_contains "dryrun shows deny list" "Bash,WebFetch,WebSearch" "$DRY_OUT"
assert_contains "dryrun prompt has findings format" "NO FINDINGS" "$DRY_OUT"
assert_contains "dryrun shows checklist" "shell=True" "$DRY_OUT"