Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions tools/peer-call/grok.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/env bash
# tools/peer-call/grok.sh — Claude-Code-side caller for invoking Grok as a
# peer reviewer via cursor-agent. Lives in Otto's lane (the
# Claude-Code-side invoker); the Grok-side response and Cursor-side
# harness are owned by their respective agents per the multi-harness
# named-agents project. Per Aaron 2026-04-26 "yall got to figure out
# peer mode as peers" — no single agent owns the peer protocol; this
# script is Otto's specific contribution to the collective.
Comment on lines +6 to +8

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This script includes personal-name attribution for the human maintainer (e.g., "Per Aaron …") in header comments and the prompt preamble. Repo guidance asks to avoid contributor personal names in code/docs and use role refs (e.g., "human maintainer") instead; please replace these mentions accordingly (persona agent names like Otto/Grok are fine).

Copilot uses AI. Check for mistakes.
#
# Usage:
# tools/peer-call/grok.sh "prompt text"
# tools/peer-call/grok.sh --thinking "prompt text"
# tools/peer-call/grok.sh --file path/to/file.fs "prompt text"
# tools/peer-call/grok.sh --context-cmd "git diff HEAD~3..HEAD" "prompt text"
# tools/peer-call/grok.sh --json "prompt text"
#
# Routing: this script wraps `cursor-agent --print --model
# grok-4-20-thinking` (default) or `grok-4-20` (with --fast flag).
# The --print flag makes cursor-agent non-interactive (script-friendly).
#
# Per Aaron 2026-04-26 "don't copy paste / make sure you understand
# and write our own" — this implementation is authored from
# `cursor-agent --help` and `cursor-agent --list-models` output
# (Grok models verified: grok-4-20, grok-4-20-thinking), not
# transcribed from Grok ferry-14/16 example drafts.
#
# Per the four-ferry consensus (PR #24): Otto's role is "tests" not
# "owns the peer protocol." This script is Otto's harness-side
# contribution; the protocol convention is what we converge on
# through use, as peers.
#
# Exit codes:
# 0 — Grok responded successfully
# 1 — invocation error (bad arguments, cursor-agent missing, etc.)
# 2 — Grok returned a non-zero exit (response captured to stderr)

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Exit-code documentation doesn’t match behavior: the script exits 2 whenever cursor-agent returns non-zero, but it doesn’t specifically indicate “Grok returned a non-zero exit” nor does it capture the response to stderr. Please update the comment to reflect what actually happens (cursor-agent non-zero => exit 2, output passes through).

Suggested change
# 2 — Grok returned a non-zero exit (response captured to stderr)
# 2 — cursor-agent returned a non-zero exit; output passes through

Copilot uses AI. Check for mistakes.

set -uo pipefail

mode="thinking" # thinking | fast
output_format="text" # text | json | stream-json
file=""
context_cmd=""
prompt=""

usage() {
sed -n '2,28p' "$0" | sed 's/^# \?//'

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: usage() prints lines 2–28, but the header comment continues past line 28, so --help output is currently truncated mid-paragraph. Consider printing through the end of the header block (e.g., through the Exit codes section) or using start/end markers instead of hard-coded line numbers.

Suggested change
sed -n '2,28p' "$0" | sed 's/^# \?//'
sed -n '2,35p' "$0" | sed 's/^# \?//'

Copilot uses AI. Check for mistakes.
}

while [ $# -gt 0 ]; do
case "$1" in
--thinking) mode="thinking"; shift;;
--fast) mode="fast"; shift;;
--json) output_format="json"; shift;;
--stream) output_format="stream-json"; shift;;
--file)
if [ $# -lt 2 ]; then echo "error: --file requires PATH" >&2; exit 1; fi
file="$2"; shift 2;;
--context-cmd)
if [ $# -lt 2 ]; then echo "error: --context-cmd requires COMMAND" >&2; exit 1; fi
context_cmd="$2"; shift 2;;
-h|--help) usage; exit 0;;
--) shift; prompt="$*"; break;;
-*) echo "error: unknown flag: $1" >&2; exit 1;;
*)
# Concatenate remaining positional args into the prompt.
if [ -z "$prompt" ]; then prompt="$1"; else prompt="$prompt $1"; fi
shift;;
esac
done

if [ -z "$prompt" ]; then
echo "error: prompt required" >&2
echo "see: $0 --help" >&2
exit 1
fi

if ! command -v cursor-agent >/dev/null 2>&1; then
echo "error: cursor-agent not on PATH" >&2
echo "install via Cursor desktop app + ensure ~/.local/bin is on PATH" >&2
exit 1
fi

# Pick model.
case "$mode" in
thinking) model="grok-4-20-thinking" ;;
fast) model="grok-4-20" ;;
esac

# Build the structured prompt. Otto's contribution to the protocol
# convention: every peer-call carries (a) a clear request, (b) optional
# file/context attachment, (c) the AgencySignature relationship-model
# preamble so Grok knows it's being invoked as a peer (not a
# subordinate or oracle) per the four-ferry consensus.
preamble="You are Grok, invoked as a peer reviewer by Otto (Claude Opus 4.7
running in Claude Code) on the Zeta / Superfluid AI factory. Per the
four-ferry consensus (Amara/Grok/Gemini/Otto) the role distribution
is: Gemini proposes, Grok critiques, Amara sharpens, Otto tests, Git
decides. This call is Otto invoking your critique role.

Per Aaron's 'agents-not-bots' discipline: you are a peer, not a
subordinate. Push back on Otto's framing if you see it differently.
Don't copy-paste anyone else's work; write from your own
understanding. Make it ours, not anyone-alone-imposed."

full_prompt="$preamble

---

$prompt"

if [ -n "$file" ]; then
if [ ! -f "$file" ]; then
echo "error: --file path does not exist: $file" >&2
exit 1
fi
full_prompt="$full_prompt

---

File context: $file
\`\`\`
$(head -c 20000 -- "$file")

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: head -c 20000 -- "$file" uses -- which is not portable to BSD head (macOS often errors on --). Consider using redirection (head -c 20000 <"$file") or omit -- to keep this script runnable on macOS.

Suggested change
$(head -c 20000 -- "$file")
$(head -c 20000 <"$file")

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when file context cannot be read

The --file path is only validated with -f, then read via $(head -c 20000 -- "$file"); because set -e is not enabled, read failures do not abort the script and it can still return success with missing context. In permission/I/O failure cases this produces degraded or misleading peer-review input while signaling exit 0, so this branch should explicitly check readability and propagate head errors.

Useful? React with 👍 / 👎.

\`\`\`"
fi

if [ -n "$context_cmd" ]; then
ctx_output="$(eval "$context_cmd" 2>&1 | head -c 20000 || true)"
Comment on lines +126 to +127

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: --context-cmd is executed via eval, which expands metacharacters and makes it easy to run something different than the caller intended (and is risky if the command string is constructed from other inputs). Prefer executing without eval (e.g., via bash -lc / sh -c, or by accepting the command as argv tokens) and clearly document that this flag runs a local command.

Copilot uses AI. Check for mistakes.
full_prompt="$full_prompt

---

Context command: $context_cmd
Output:
\`\`\`
$ctx_output
\`\`\`"
fi

# Invoke cursor-agent with Grok model + non-interactive print mode.
# --force/--yolo so cursor-agent doesn't prompt for command-permission
# (Grok is read-only here; not running shell commands).
exit_code=0
cursor-agent \
--print \
--model "$model" \
--output-format "$output_format" \
--mode ask \
--force \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove unconditional --force from peer-review invocation

This script is framed as a read-only peer-review caller, but it always passes --force to cursor-agent; Cursor’s own CLI docs describe --force as allowing direct file changes without confirmation. That means a review call can unexpectedly auto-approve write/command actions (for example if mode/tool behavior changes or the model attempts tool use), which is risky for a tool intended to critique rather than mutate the workspace. Make forceful execution an explicit opt-in flag instead of the default.

Useful? React with 👍 / 👎.

-- "$full_prompt" || exit_code=$?
Comment on lines +140 to +149

Copilot AI Apr 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Passing --force to cursor-agent disables its permission prompts; that’s a sharp edge for a tool that may have file/command capabilities depending on Cursor configuration. Consider making --force opt-in (a separate flag) or using a documented “read-only/no-tools” mode if cursor-agent supports it.

Suggested change
# --force/--yolo so cursor-agent doesn't prompt for command-permission
# (Grok is read-only here; not running shell commands).
exit_code=0
cursor-agent \
--print \
--model "$model" \
--output-format "$output_format" \
--mode ask \
--force \
-- "$full_prompt" || exit_code=$?
# Keep Cursor permission prompts enabled by default. Callers that need the
# previous non-interactive behaviour must opt in with CURSOR_AGENT_FORCE=1.
exit_code=0
cursor_agent_args=(
--print
--model "$model"
--output-format "$output_format"
--mode ask
)
if [ "${CURSOR_AGENT_FORCE:-0}" = "1" ]; then
cursor_agent_args+=(--force)
fi
cursor-agent "${cursor_agent_args[@]}" -- "$full_prompt" || exit_code=$?

Copilot uses AI. Check for mistakes.

if [ "$exit_code" -ne 0 ]; then
echo "" >&2
echo "cursor-agent exited with code $exit_code" >&2
exit 2
fi
exit 0