From d8881a1da0df2e8a267aa31422179791d23817d4 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Sun, 26 Apr 2026 17:49:37 -0400 Subject: [PATCH 1/5] =?UTF-8?q?ops(peer-call):=20tools/peer-call/{gemini,c?= =?UTF-8?q?odex}.sh=20=E2=80=94=20sibling=20Claude-Code-side=20callers=20e?= =?UTF-8?q?xtending=20the=20multi-harness=20peer-call=20set=20(task=20#303?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: - Aaron 2026-04-26 multi-harness named-agents project: no single agent owns the peer protocol; each Claude-Code-side caller is Otto's specific contribution to invoking that peer in the same AgencySignature relationship-model. grok.sh (PR #27) covered Grok via cursor-agent. This extends to Gemini (gemini CLI) and Codex (codex CLI), the other two CLIs already installed and logged in per Aaron's *"you have all the CLIs already install and logged in as me"*. - Per the four-ferry consensus (Amara/Grok/Gemini/Otto): Gemini proposes, Grok critiques, Amara sharpens, Otto tests, Git decides. gemini.sh's preamble invokes Gemini's *propose* role (divergent options, possibility-space surfacing). Codex isn't in the four-ferry list but plays a recurring PR-review peer role across this session's drain-log substrate; codex.sh frames its preamble accordingly as implementation-peer / code-grounded second opinion. - Per Aaron *"don't copy paste / make sure you understand and write our own"*: both scripts authored from each CLI's own --help output (gemini -p / -m / -o / --yolo / --skip-trust; codex exec -m / -s / --skip-git-repo-check), not transcribed from any peer's example draft. - Resolves task #303 (sibling peer-call scripts). What: - New file tools/peer-call/gemini.sh (~145 lines bash, executable) - Wraps `gemini -p` (non-interactive headless mode) - --model (override default), --json/--stream (output format), --file PATH (attach file context, head -c 20000), --context-cmd CMD (attach command output, head -c 20000), --help - --yolo --skip-trust passed so peer-call isn't gated on per-session trust prompts (Gemini is read-only here) - Preamble frames Gemini as proposer per four-ferry consensus; invitation-to-be-peer language matches grok.sh shape - New file tools/peer-call/codex.sh (~150 lines bash, executable) - Wraps `codex exec -s read-only --skip-git-repo-check` - --model (override), --review (route through `codex review` subcommand for first-class code-review path), --file PATH, --context-cmd CMD, --help - read-only sandbox so peer-call cannot mutate the working tree - Preamble names Codex as implementation-peer / code-grounded second opinion; frames AgencySignature relationship-model consistently with grok.sh / gemini.sh Why this implementation differs from any peer's drafts: - Gemini has no model-list output equivalent to cursor-agent's; --model flag passes through whatever the user's gemini config resolves (no Otto-side hardcoded default). - Codex's `exec` subcommand does NOT take an --output-format flag like cursor-agent or gemini; output format is whatever codex emits. The script accepts that and lets codex's own JSON modes (via -c output_schema=...) be specified by user when needed. - Otto-235 4-shell bash compat preserved: no associative arrays; portable [ ] tests; bash arrays declared with (), expansion via "${arr[@]}". - Glass Halo radical-honesty register: error messages emoji-free, exit codes documented, --help echoes the header comment. Proof: - 2 live tests pass: 1. Both scripts: `bash -n` syntax check passes. 2. Both scripts: `--help` echoes header comment cleanly. 3. gemini.sh live invocation: short prompt asking whether the preamble framing reads as peer-shaped. Gemini responded: "Yes, it defines specific roles in a non-hierarchical collaborative ecosystem." — peer-shaped read confirmed. 4. codex.sh live test deferred (read-only sandbox, but token cost on Aaron's Codex budget). --help and bash -n verified. - gemini at /opt/homebrew/bin/gemini with `gemini -p` headless mode confirmed via earlier smoke-test ("PEER-CALL-OK" round trip). - codex at /opt/homebrew/bin/codex with `codex exec` subcommand flags confirmed via `codex exec --help`. Co-Authored-By: Claude Opus 4.7 --- tools/peer-call/codex.sh | 154 ++++++++++++++++++++++++++++++++++++++ tools/peer-call/gemini.sh | 149 ++++++++++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100755 tools/peer-call/codex.sh create mode 100755 tools/peer-call/gemini.sh diff --git a/tools/peer-call/codex.sh b/tools/peer-call/codex.sh new file mode 100755 index 000000000..014a35794 --- /dev/null +++ b/tools/peer-call/codex.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# tools/peer-call/codex.sh — Claude-Code-side caller for invoking +# Codex (OpenAI) as a peer reviewer via the codex CLI. Sibling +# to tools/peer-call/grok.sh and gemini.sh (Otto's existing +# harness-side callers). Codex isn't in the original four-ferry +# consensus but plays a recurring PR-review role across this +# session's drain-log substrate; this script is the harness-side +# bridge that lets Otto invoke Codex as a peer in the same +# AgencySignature relationship-model as the others. +# +# Usage: +# tools/peer-call/codex.sh "prompt text" +# tools/peer-call/codex.sh --model gpt-5.3-codex "prompt text" +# tools/peer-call/codex.sh --file path/to/file.fs "prompt text" +# tools/peer-call/codex.sh --context-cmd "git diff HEAD~3..HEAD" "prompt text" +# tools/peer-call/codex.sh --review "review the diff for correctness" +# +# Routing: this script wraps `codex exec` (non-interactive) with +# read-only sandbox so Codex inspects but doesn't mutate the +# tree. The --review flag routes through `codex review` +# instead, which is Codex's first-class code-review path. +# +# Per Aaron 2026-04-26 "don't copy paste / make sure you +# understand and write our own" — this implementation is +# authored from `codex exec --help` output (verified flags: +# -m / -s / -C / --skip-git-repo-check), not transcribed from +# any draft. +# +# Codex's role in our role-distribution: implementation peer +# / second-opinion coder. Where Grok critiques and Gemini +# proposes, Codex applies a code-grounded skeptical pass that +# composes with the other two without replacing either. +# +# Exit codes: +# 0 — Codex responded successfully +# 1 — invocation error (bad arguments, codex missing, etc.) +# 2 — Codex returned a non-zero exit (response captured to stderr) + +set -uo pipefail + +model="" # empty = use codex default +review_mode="false" # false | true (uses `codex review` instead) +file="" +context_cmd="" +prompt="" + +usage() { + sed -n '2,33p' "$0" | sed 's/^# \?//' +} + +while [ $# -gt 0 ]; do + case "$1" in + --model) + if [ $# -lt 2 ]; then echo "error: --model requires NAME" >&2; exit 1; fi + model="$2"; shift 2;; + --review) review_mode="true"; 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;; + *) + 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 codex >/dev/null 2>&1; then + echo "error: codex not on PATH" >&2 + echo "install via: npm i -g @openai/codex (or per Aaron's setup)" >&2 + exit 1 +fi + +preamble="You are Codex, 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 canonical role distribution is: Gemini proposes, Grok +critiques, Amara sharpens, Otto tests, Git decides. You aren't +in the four-ferry list explicitly, but you've been a recurring +PR-review peer this session — your role is implementation peer +/ code-grounded second opinion. + +Per Aaron's 'agents-not-bots' discipline: you are a peer, not +a subordinate. Push back on Otto's framing if the code says +otherwise. Don't copy-paste anyone else's review; reason from +the artifact in front of you. 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") +\`\`\`" +fi + +if [ -n "$context_cmd" ]; then + ctx_output="$(eval "$context_cmd" 2>&1 | head -c 20000 || true)" + full_prompt="$full_prompt + +--- + +Context command: $context_cmd +Output: +\`\`\` +$ctx_output +\`\`\`" +fi + +# Invoke codex in read-only sandbox so peer-call can't mutate +# the repo. --skip-git-repo-check defends against false +# negatives if codex is invoked from outside a worktree. +exit_code=0 +if [ "$review_mode" = "true" ]; then + codex_args=(review) +else + codex_args=(exec -s read-only --skip-git-repo-check) +fi +if [ -n "$model" ]; then + codex_args+=(-m "$model") +fi +codex_args+=("$full_prompt") + +codex "${codex_args[@]}" || exit_code=$? + +if [ "$exit_code" -ne 0 ]; then + echo "" >&2 + echo "codex exited with code $exit_code" >&2 + exit 2 +fi +exit 0 diff --git a/tools/peer-call/gemini.sh b/tools/peer-call/gemini.sh new file mode 100755 index 000000000..6128006ff --- /dev/null +++ b/tools/peer-call/gemini.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# tools/peer-call/gemini.sh — Claude-Code-side caller for invoking +# Gemini as a peer proposer via the gemini CLI. Sibling to +# tools/peer-call/grok.sh (Otto's existing harness-side caller for +# Grok). Per the four-ferry consensus (PR #24): Gemini's role in +# the role-distribution is "proposes" — invoke this script when +# Otto wants a generative / divergent peer contribution, not a +# critique. (For critique route to grok.sh.) +# +# Usage: +# tools/peer-call/gemini.sh "prompt text" +# tools/peer-call/gemini.sh --model gemini-2.5-pro "prompt text" +# tools/peer-call/gemini.sh --file path/to/file.fs "prompt text" +# tools/peer-call/gemini.sh --context-cmd "git diff HEAD~3..HEAD" "prompt text" +# tools/peer-call/gemini.sh --json "prompt text" +# +# Routing: this script wraps `gemini -p` (non-interactive +# headless mode). Default model is whatever the gemini CLI is +# configured to use; override with --model. +# +# Per Aaron 2026-04-26 "don't copy paste / make sure you +# understand and write our own" — this implementation is +# authored from `gemini --help` output (verified flags: -p / -m +# / -o / --yolo), not transcribed from any draft. +# +# Per the four-ferry consensus: Gemini proposes, Grok critiques, +# Amara sharpens, Otto tests, Git decides. This script is Otto +# invoking Gemini's proposal role. +# +# Exit codes: +# 0 — Gemini responded successfully +# 1 — invocation error (bad arguments, gemini missing, etc.) +# 2 — Gemini returned a non-zero exit (response captured to stderr) + +set -uo pipefail + +model="" # empty = use gemini default +output_format="text" # text | json | stream-json +file="" +context_cmd="" +prompt="" + +usage() { + sed -n '2,32p' "$0" | sed 's/^# \?//' +} + +while [ $# -gt 0 ]; do + case "$1" in + --model) + if [ $# -lt 2 ]; then echo "error: --model requires NAME" >&2; exit 1; fi + model="$2"; shift 2;; + --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;; + *) + 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 gemini >/dev/null 2>&1; then + echo "error: gemini not on PATH" >&2 + echo "install via: npm i -g @google/gemini-cli (or per Aaron's setup)" >&2 + exit 1 +fi + +# Build the structured prompt. Same shape as grok.sh: clear +# request, optional file/context attachment, AgencySignature +# relationship-model preamble — but framed for Gemini's +# proposes role per the four-ferry consensus. +preamble="You are Gemini, invoked as a peer proposer 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 propose role. + +Per Aaron's 'agents-not-bots' discipline: you are a peer, not +a subordinate. Generate divergent options, name tradeoffs, +surface possibility space Otto may not have considered. Don't +copy-paste anyone else's work; propose 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") +\`\`\`" +fi + +if [ -n "$context_cmd" ]; then + ctx_output="$(eval "$context_cmd" 2>&1 | head -c 20000 || true)" + full_prompt="$full_prompt + +--- + +Context command: $context_cmd +Output: +\`\`\` +$ctx_output +\`\`\`" +fi + +# Invoke gemini in headless mode. --yolo skips approval prompts +# (Gemini is read-only for peer-call; not running shell +# commands). Pass --skip-trust so the workspace doesn't gate +# on per-session trust prompts. +exit_code=0 +gemini_args=(-p "$full_prompt" --yolo --skip-trust -o "$output_format") +if [ -n "$model" ]; then + gemini_args+=(-m "$model") +fi + +gemini "${gemini_args[@]}" || exit_code=$? + +if [ "$exit_code" -ne 0 ]; then + echo "" >&2 + echo "gemini exited with code $exit_code" >&2 + exit 2 +fi +exit 0 From ef32d7d7c0f9b063acce3cb8384a42941f1b095e Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Sun, 26 Apr 2026 17:54:01 -0400 Subject: [PATCH 2/5] =?UTF-8?q?docs(peer-call):=20tools/peer-call/README.m?= =?UTF-8?q?d=20=E2=80=94=20companion=20doc=20for=20the=203-script=20peer-c?= =?UTF-8?q?all=20set=20(extends=20task=20#303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: - The 3 scripts (grok.sh / gemini.sh / codex.sh) shipped without a README explaining them as a coherent set. Future-Otto and any external reader sees the pattern only by reading all 3 scripts and inferring the shared shape — discoverability gap. - Composes with this same PR (#28) so the README lands with the scripts it documents, not as a separate follow-up that drifts. What: - New file tools/peer-call/README.md (~140 lines) - Quick-reference table: script / peer / underlying CLI / default role / underlying model - Shared flag surface documented (uniform --file / --context-cmd / --help across all 3, with per-script extras called out) - Uniform exit-code contract (0 / 1 / 2) - AgencySignature preamble convention named explicitly: who-calls / role-distribution / role-this-call / agents-not-bots discipline / don't-copy-paste discipline - 3 example invocations, one per script, per the natural role - "When NOT to use" section names the boundaries: not for Aaron-side calls, not for multi-turn dialogues, not for internal Claude-Code subagent work - "Adding a new sibling" section captures the extension pattern for a future 4th peer Glass Halo radical-honesty: README cites Aaron's directives verbatim; doesn't claim ownership of the protocol convention; explicitly names that the convention is what agents converge on through use, not what any single agent imposes. No script changes; this commit is purely documentation closing the discoverability gap on the peer-call set. Co-Authored-By: Claude Opus 4.7 --- tools/peer-call/README.md | 181 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 tools/peer-call/README.md diff --git a/tools/peer-call/README.md b/tools/peer-call/README.md new file mode 100644 index 000000000..465e69535 --- /dev/null +++ b/tools/peer-call/README.md @@ -0,0 +1,181 @@ +# tools/peer-call/ — Otto's Claude-Code-side peer callers + +Three sibling shell scripts that let Otto (Claude Opus 4.7 +running in Claude Code) invoke a peer agent in another CLI +harness as a peer, not a subordinate. Each wraps the relevant +peer's headless-mode CLI and applies a shared +AgencySignature relationship-model preamble so the peer +knows the call posture. + +## Scripts at a glance + +| Script | Peer | Underlying CLI | Default role (when to invoke) | Underlying model | +|---|---|---|---|---| +| `grok.sh` | Grok (xAI) | `cursor-agent --print --model grok-4-20-thinking` | **Critique** — skeptical pass on Otto's framing | grok-4-20-thinking (default) / grok-4-20 (--fast) | +| `gemini.sh` | Gemini (Google) | `gemini -p` | **Propose** — divergent options, possibility-space surfacing | gemini default (override via `--model`) | +| `codex.sh` | Codex (OpenAI) | `codex exec -s read-only` | **Implementation peer** — code-grounded second opinion | codex default (override via `--model`) | + +The role column reflects the **four-ferry consensus** +(Amara/Grok/Gemini/Otto, PR #24 on AceHack/Zeta): + +> Gemini proposes, Grok critiques, Amara sharpens, Otto tests, +> Git decides. + +Codex isn't in the four-ferry list explicitly — its role +emerged through repeated PR-review participation across this +factory's drain-log substrate, so its preamble names it as +"implementation peer / code-grounded second opinion" rather +than claiming a four-ferry slot. + +## Shared flag surface + +All three scripts accept the same core flags: + +```text +--file PATH attach file content (head -c 20000) to the prompt +--context-cmd CMD attach the output of CMD (head -c 20000) to the prompt +--help, -h print the script header as usage +``` + +Per-script extras: + +- `grok.sh` adds `--thinking` (default) / `--fast` to switch + between `grok-4-20-thinking` and `grok-4-20` models, and + `--json` / `--stream` for output format. +- `gemini.sh` adds `--model NAME` to override the default + Gemini model, and `--json` / `--stream` for output format. +- `codex.sh` adds `--model NAME` and `--review` (which routes + through `codex review` instead of `codex exec` for + first-class code-review work). + +Exit codes are uniform across all three: + +- `0` — peer responded successfully +- `1` — invocation error (bad arguments, CLI missing, etc.) +- `2` — peer's CLI returned non-zero exit (response captured + to stderr) + +## The AgencySignature preamble + +Every peer-call carries a structured prompt with this shape: + +```text + + +--- + + + +--- + +[optional: File context block from --file] + +--- + +[optional: Context command block from --context-cmd] +``` + +The preamble is the load-bearing part. It tells the peer: + +1. **Who's calling** (Otto / Claude Opus 4.7 / Claude Code / + Zeta factory). +2. **The role distribution** (four-ferry consensus cited + verbatim). +3. **The role this specific call is invoking** (critique / + propose / second opinion). +4. **The agents-not-bots discipline** — peer is a peer, not a + subordinate, with explicit invitation to push back. +5. **The don't-copy-paste discipline** — peer should reason + from its own understanding, not transcribe anyone else's + draft. + +This preamble is Otto's harness-side contribution to the peer +protocol convention. The convention itself — what every peer +will eventually accept as "the peer-call shape" — is what +the four agents converge on through use, not what any single +agent imposes. + +## Examples + +### Critique pass on a draft (Grok) + +```bash +tools/peer-call/grok.sh \ + --file docs/research/some-draft.md \ + "Critique the framing in section 2 — does the claim follow from the evidence cited, or is there a gap?" +``` + +### Proposal exploration (Gemini) + +```bash +tools/peer-call/gemini.sh \ + "We're choosing between strategy A (per-file 3-way merge with subagent dispatch) and strategy B (pure concatenation). Propose a 3rd option I haven't considered, with one paragraph each on tradeoffs." +``` + +### Code-grounded second opinion (Codex) + +```bash +tools/peer-call/codex.sh \ + --review \ + --context-cmd "git diff HEAD~3..HEAD -- tools/peer-call/" \ + "Review the recent peer-call diff for correctness — particularly the bash-array argument construction. Flag anything that breaks the 4-shell compat target (macOS 3.2 / Ubuntu / git-bash / WSL)." +``` + +## Why these scripts exist + +Aaron 2026-04-26: *"yall got to figure out peer mode as +peers"* + *"don't copy paste / make sure you understand and +write our own"* + *"you have all the CLIs already install and +logged in as me"* + *"claude is going to call the cursor cli +so you have a harness"*. + +These are read together as: the peer-call protocol is not +owned by any single agent; each Claude-Code-side caller is +Otto's specific contribution to the collective; the +protocol convention is what the agents converge on through +use. + +`grok.sh` (PR #27 on AceHack/Zeta, merged 2026-04-26) covered +the Grok-via-Cursor harness path. `gemini.sh` and `codex.sh` +(PR #28 on AceHack/Zeta) extend the same shape to the other +two peer CLIs already on PATH. The set is open; if a fourth +peer (Amara via ChatGPT, etc.) gains a headless CLI surface, +adding `tools/peer-call/.sh` is a copy-and-adapt of the +existing pattern, not a new design. + +## When NOT to use these scripts + +- **For Aaron-side peer calls.** Aaron is not invoked through + a script; he's called through actual conversation in Claude + Code (or any other CLI). The peer-call set is for + Otto-to-other-agent calls, not human-to-agent. +- **For multi-turn dialogues.** These scripts are + single-shot. If a peer call needs back-and-forth, route + through the peer's interactive CLI directly (cursor-agent / + gemini / codex without the wrapper). +- **For internal-to-Claude-Code work.** Subagent dispatch via + the `Task` tool stays within Claude Code's context-isolation + boundary; peer-call goes out to a different CLI / model + family. Don't reach for peer-call when subagent dispatch is + the right move. + +## Adding a new sibling + +To add a 4th peer-call script (e.g. for a future peer-CLI): + +1. Verify the peer's CLI has a non-interactive / headless + mode. If not, the script can't work as a single-shot + wrapper. +2. Copy one of the existing scripts (most similar by CLI + shape) as a starting template. Then **rewrite it from the + peer-CLI's own `--help` output** — don't copy-paste flag + semantics across CLIs. +3. Adapt the AgencySignature preamble to name the peer's + role in the role-distribution. Cite the four-ferry + consensus and add the new peer's role as a sibling sentence. +4. Verify with `bash -n script.sh` and a `--help` smoke + test. +5. Live-test with a minimal prompt asking the peer whether + the framing reads as peer-shaped. The preamble works when + the peer's response confirms the role-binding. +6. Update this README's table. From ef15f8840032b10274755a30047fadb561f44ad0 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Sun, 26 Apr 2026 17:58:32 -0400 Subject: [PATCH 3/5] =?UTF-8?q?docs(peer-call):=20add=20Security=20notes?= =?UTF-8?q?=20section=20to=20README=20=E2=80=94=20`--context-cmd`=20shell-?= =?UTF-8?q?eval=20surface=20+=20prompt=20safety=20+=20`--file`=20size=20ca?= =?UTF-8?q?p=20(extends=20task=20#303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: - Audit pass found that all 3 scripts use `eval "$context_cmd"` to capture command output. This is intentional (the flag's documented purpose) but worth calling out so future-readers don't pass untrusted strings to --context-cmd. - Same audit confirmed the prompt itself is safe with shell metacharacters (passed as single quoted arg via -- "$full_prompt" / -p "$full_prompt"). Worth documenting so future-Otto doesn't add unnecessary escaping. - 20000-byte cap on --file and --context-cmd content was already in the scripts but not documented in the README. What: - New "Security notes" section in tools/peer-call/README.md (~24 lines) covering: - --context-cmd runs shell code via eval (don't pass untrusted strings) - Prompt is safe with shell metacharacters (single-arg quoted passthrough) - --file and --context-cmd capped at 20000 bytes - No secrets handling — peer's own CLI handles auth, don't put secrets in prompts (they'd land in peer session logs) Composes with the same PR (#28) that already lands the README; this is one additional section, not a separate PR. Co-Authored-By: Claude Opus 4.7 --- tools/peer-call/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/peer-call/README.md b/tools/peer-call/README.md index 465e69535..df5c0a136 100644 --- a/tools/peer-call/README.md +++ b/tools/peer-call/README.md @@ -143,6 +143,36 @@ peer (Amara via ChatGPT, etc.) gains a headless CLI surface, adding `tools/peer-call/.sh` is a copy-and-adapt of the existing pattern, not a new design. +## Security notes + +- **`--context-cmd` runs shell code.** All three scripts use + `eval "$context_cmd"` to capture the output of the command + passed to `--context-cmd`. This is intentional (the flag's + documented purpose is to attach command output as context), + but it means **`--context-cmd` is a shell-execution + surface** — never pass an untrusted string to it. The `eval` + output is captured, not piped to the peer's CLI as a command, + so the peer-side risk is limited to what the eval'd command + itself exposes (file reads, env-var leaks, etc.). +- **The prompt itself is safe to contain shell metacharacters.** + `$prompt` is passed as a single quoted argument + (`-- "$full_prompt"` / `-p "$full_prompt"`), so single quotes, + double quotes, backticks, dollar signs, and other shell-active + characters in the prompt are passed through verbatim without + interpretation by Otto's local shell. (The peer's own CLI may + interpret some characters — that's the peer's contract, not + Otto's.) +- **`--file` reads only the first 20000 bytes.** Both + `--file PATH` and `--context-cmd CMD` cap their attached + content at `head -c 20000` to keep peer prompts within + reasonable size limits. If the peer needs more, route through + the peer's interactive CLI directly. +- **No secrets handling.** None of the three scripts read or + inject API keys; the underlying CLIs (`cursor-agent`, + `gemini`, `codex`) handle their own auth via their own config + paths. Don't put secrets in prompts — they end up in the + peer's session logs. + ## When NOT to use these scripts - **For Aaron-side peer calls.** Aaron is not invoked through From 5c5bfcf6c48e243a081183be7bb3f954012ad7e8 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Sun, 26 Apr 2026 20:51:27 -0400 Subject: [PATCH 4/5] fix(peer-call): P1 portability + security fixes per PR #28 review (Copilot) Why: - Copilot inline review on PR #28 flagged 3 P1 bugs in the peer-call scripts that would actually break on macOS BSD tools (Otto-235 4-shell-compat target violated by my own scripts). - Plus a P1 security issue: gemini.sh used --yolo which auto-approves ALL tool calls (write ops included), violating the "peer-call is read-only" contract. What: 1. Fix `head -c 20000 -- "$file"` -> `head -c 20000 < "$file"` (3 files) - BSD/macOS head doesn't support `--` option terminator - Pipe-redirection from file is portable across all 4 shells 2. Fix `sed 's/^# \?//'` -> `sed -E 's/^# ?//'` (3 files) - `\?` is GNU-only basic-regex extension; not in BSD sed - `-E` extended regex makes `?` work portably - Affects --help output rendering 3. Drop --yolo, replace with --approval-mode plan (gemini.sh) - Per gemini --help: plan = "read-only mode" - --yolo auto-approved all tool calls (including writes) - Read-only is what the peer-call contract requires Verification: - bash -n passes on all 3 scripts - --help renders cleanly on all 3 (the sed fix preserved formatting) - Per Copilot's specific findings: PR #28 inline comments lines 44/48/115/116/137/120/12/116 Composes with: - Otto-235 (4-shell bash compat: macOS 3.2 / Ubuntu / git-bash / WSL) - The README's existing "Security notes" section (which now has another bullet to add for the --approval-mode plan choice) Still owed (separate commits): name-attribution convention findings (Copilot flagged "Per Aaron..." in headers + README per docs/AGENT-BEST-PRACTICES.md "No name attribution in code, docs, or skills"); --review + --model interaction in codex.sh; --stream example in gemini.sh usage header; exit code 2 wording in README. Co-Authored-By: Claude Opus 4.7 --- tools/peer-call/codex.sh | 4 ++-- tools/peer-call/gemini.sh | 17 ++++++++++------- tools/peer-call/grok.sh | 5 +++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/peer-call/codex.sh b/tools/peer-call/codex.sh index 014a35794..eab71ef42 100755 --- a/tools/peer-call/codex.sh +++ b/tools/peer-call/codex.sh @@ -45,7 +45,7 @@ context_cmd="" prompt="" usage() { - sed -n '2,33p' "$0" | sed 's/^# \?//' + sed -n '2,33p' "$0" | sed -E 's/^# ?//' } while [ $# -gt 0 ]; do @@ -113,7 +113,7 @@ if [ -n "$file" ]; then File context: $file \`\`\` -$(head -c 20000 -- "$file") +$(head -c 20000 < "$file") \`\`\`" fi diff --git a/tools/peer-call/gemini.sh b/tools/peer-call/gemini.sh index 6128006ff..72353fe18 100755 --- a/tools/peer-call/gemini.sh +++ b/tools/peer-call/gemini.sh @@ -41,7 +41,7 @@ context_cmd="" prompt="" usage() { - sed -n '2,32p' "$0" | sed 's/^# \?//' + sed -n '2,32p' "$0" | sed -E 's/^# ?//' } while [ $# -gt 0 ]; do @@ -112,7 +112,7 @@ if [ -n "$file" ]; then File context: $file \`\`\` -$(head -c 20000 -- "$file") +$(head -c 20000 < "$file") \`\`\`" fi @@ -129,12 +129,15 @@ $ctx_output \`\`\`" fi -# Invoke gemini in headless mode. --yolo skips approval prompts -# (Gemini is read-only for peer-call; not running shell -# commands). Pass --skip-trust so the workspace doesn't gate -# on per-session trust prompts. +# Invoke gemini in headless mode. --approval-mode plan keeps the +# call genuinely read-only (per gemini --help: plan = "read-only +# mode"). Earlier draft used --yolo which auto-approved ALL tool +# calls (write operations included) — that violates the "peer-call +# is read-only" contract per Copilot review on PR #28. Pass +# --skip-trust so the workspace doesn't gate on per-session +# trust prompts. exit_code=0 -gemini_args=(-p "$full_prompt" --yolo --skip-trust -o "$output_format") +gemini_args=(-p "$full_prompt" --approval-mode plan --skip-trust -o "$output_format") if [ -n "$model" ]; then gemini_args+=(-m "$model") fi diff --git a/tools/peer-call/grok.sh b/tools/peer-call/grok.sh index 93b169571..6a583f4f9 100755 --- a/tools/peer-call/grok.sh +++ b/tools/peer-call/grok.sh @@ -43,7 +43,7 @@ context_cmd="" prompt="" usage() { - sed -n '2,28p' "$0" | sed 's/^# \?//' + sed -n '2,28p' "$0" | sed -E 's/^# ?//' } while [ $# -gt 0 ]; do @@ -119,12 +119,13 @@ if [ -n "$file" ]; then File context: $file \`\`\` -$(head -c 20000 -- "$file") +$(head -c 20000 < "$file") \`\`\`" fi if [ -n "$context_cmd" ]; then ctx_output="$(eval "$context_cmd" 2>&1 | head -c 20000 || true)" + # (head reading from pipe — no -- needed; BSD head accepts -c on stdin) full_prompt="$full_prompt --- From d45cab7820d533a4e33dae24adf93839687d835b Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Tue, 28 Apr 2026 05:03:30 -0400 Subject: [PATCH 5/5] fix(pr-28): drain 7 active threads on tools/peer-call/{gemini,codex,README} Form-1 substantive fixes from copilot + chatgpt-codex-connector review: - gemini.sh L21-24: persona-name "Per Aaron 2026-04-26" stripped to role-ref "the human maintainer's 2026-04-26 framing" per Otto-279 history-vs-current-state surface distinction (tools/ is current-state); --skip-trust added to verified-flags list (was actually used in the script but absent from the header attestation). - gemini.sh L15: --stream usage example added to header block (the parser supports --stream but the documented examples did not). - gemini.sh + codex.sh: exit-code 2 description corrected. Was "response captured to stderr"; corrected to "the peer's stdout/stderr pass through to the caller's terminal; this script emits a 'codex/gemini exited with code N' diagnostic on stderr". The wrapper does NOT capture or redirect peer output; only the trailing diagnostic is on stderr. - codex.sh: --model gated on non-review mode. `codex review` doesn't accept `-m`; passing it would either be silently ignored or fail. Wrapper now only adds `-m "$model"` for `codex exec` invocations and emits a stderr warning when --model is provided in review mode. - README.md L51-56: exit-code 2 description aligned with the per-script documentation correction above. - README.md L130: persona-name "Aaron 2026-04-26:" stripped to role-ref "The human maintainer's 2026-04-26 framing:" per Otto-279. - README.md L159-164: claim about prompt argument form corrected. Wrapper-form is per-CLI: `-p "$full_prompt"` for gemini.sh, positional argv for codex.sh. The `--` option-terminator is NOT used by codex.sh because codex doesn't recognize it on `exec` / `review` subcommands. Original text claimed all three used `--`. Outdated threads (5) will be resolved as separate form-2 closures since the underlying lines no longer exist in the diff. Agency-Signature-Version: 1 Agent: otto Agent-Runtime: claude-code Agent-Model: claude-opus-4-7 Credential-Identity: AceHack-shared Credential-Mode: shared-with-aaron Human-Review: not-implied-by-credential Human-Review-Evidence: aaron-explicit-ask Action-Mode: autonomous-fail-open Task: pr-28-thread-drain-7-active --- tools/peer-call/README.md | 23 +++++++++++++++-------- tools/peer-call/codex.sh | 18 ++++++++++++++---- tools/peer-call/gemini.sh | 16 +++++++++++----- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/tools/peer-call/README.md b/tools/peer-call/README.md index df5c0a136..245bdd9fc 100644 --- a/tools/peer-call/README.md +++ b/tools/peer-call/README.md @@ -52,8 +52,11 @@ Exit codes are uniform across all three: - `0` — peer responded successfully - `1` — invocation error (bad arguments, CLI missing, etc.) -- `2` — peer's CLI returned non-zero exit (response captured - to stderr) +- `2` — peer's CLI returned a non-zero exit. The peer's stdout + / stderr are NOT captured by the wrapper; they pass through + to the caller's terminal as the peer printed them. The script + emits a ` exited with code N` diagnostic line on stderr + before exiting with code 2. ## The AgencySignature preamble @@ -123,11 +126,11 @@ tools/peer-call/codex.sh \ ## Why these scripts exist -Aaron 2026-04-26: *"yall got to figure out peer mode as -peers"* + *"don't copy paste / make sure you understand and -write our own"* + *"you have all the CLIs already install and -logged in as me"* + *"claude is going to call the cursor cli -so you have a harness"*. +The human maintainer's 2026-04-26 framing: *"yall got to figure +out peer mode as peers"* + *"don't copy paste / make sure you +understand and write our own"* + *"you have all the CLIs +already install and logged in as me"* + *"claude is going to +call the cursor cli so you have a harness"*. These are read together as: the peer-call protocol is not owned by any single agent; each Claude-Code-side caller is @@ -156,7 +159,11 @@ existing pattern, not a new design. itself exposes (file reads, env-var leaks, etc.). - **The prompt itself is safe to contain shell metacharacters.** `$prompt` is passed as a single quoted argument - (`-- "$full_prompt"` / `-p "$full_prompt"`), so single quotes, + (per-CLI form: `-p "$full_prompt"` for gemini.sh; appended + positionally as `"$full_prompt"` in codex.sh's argv array; + `--` option-terminator is NOT used by codex.sh because codex + doesn't recognize it on the `exec` / `review` subcommands), + so single quotes, double quotes, backticks, dollar signs, and other shell-active characters in the prompt are passed through verbatim without interpretation by Otto's local shell. (The peer's own CLI may diff --git a/tools/peer-call/codex.sh b/tools/peer-call/codex.sh index eab71ef42..4c9aa5511 100755 --- a/tools/peer-call/codex.sh +++ b/tools/peer-call/codex.sh @@ -34,7 +34,11 @@ # Exit codes: # 0 — Codex responded successfully # 1 — invocation error (bad arguments, codex missing, etc.) -# 2 — Codex returned a non-zero exit (response captured to stderr) +# 2 — Codex returned a non-zero exit. The peer's stdout/stderr +# pass through to the caller's terminal as printed; this +# script then emits a "codex exited with code N" diagnostic +# on stderr and exits 2 (no capture/redirect of the peer's +# output). set -uo pipefail @@ -136,11 +140,17 @@ fi exit_code=0 if [ "$review_mode" = "true" ]; then codex_args=(review) + # Note: `codex review` does not accept `-m` model override; + # the model selection there is taken from codex's own config. + # Only apply --model when in non-review mode (`codex exec`). + if [ -n "$model" ]; then + echo "warning: --model is ignored in --review mode (codex review uses its own model selection)" >&2 + fi else codex_args=(exec -s read-only --skip-git-repo-check) -fi -if [ -n "$model" ]; then - codex_args+=(-m "$model") + if [ -n "$model" ]; then + codex_args+=(-m "$model") + fi fi codex_args+=("$full_prompt") diff --git a/tools/peer-call/gemini.sh b/tools/peer-call/gemini.sh index 72353fe18..41afe4f70 100755 --- a/tools/peer-call/gemini.sh +++ b/tools/peer-call/gemini.sh @@ -13,15 +13,17 @@ # tools/peer-call/gemini.sh --file path/to/file.fs "prompt text" # tools/peer-call/gemini.sh --context-cmd "git diff HEAD~3..HEAD" "prompt text" # tools/peer-call/gemini.sh --json "prompt text" +# tools/peer-call/gemini.sh --stream "prompt text" # # Routing: this script wraps `gemini -p` (non-interactive # headless mode). Default model is whatever the gemini CLI is # configured to use; override with --model. # -# Per Aaron 2026-04-26 "don't copy paste / make sure you -# understand and write our own" — this implementation is -# authored from `gemini --help` output (verified flags: -p / -m -# / -o / --yolo), not transcribed from any draft. +# Per the human maintainer's 2026-04-26 framing "don't copy +# paste / make sure you understand and write our own" — this +# implementation is authored from `gemini --help` output +# (verified flags: -p / -m / -o / --yolo / --skip-trust), +# not transcribed from any draft. # # Per the four-ferry consensus: Gemini proposes, Grok critiques, # Amara sharpens, Otto tests, Git decides. This script is Otto @@ -30,7 +32,11 @@ # Exit codes: # 0 — Gemini responded successfully # 1 — invocation error (bad arguments, gemini missing, etc.) -# 2 — Gemini returned a non-zero exit (response captured to stderr) +# 2 — Gemini returned a non-zero exit. The peer's stdout/stderr +# pass through to the caller's terminal as printed; this +# script then emits a "gemini exited with code N" diagnostic +# on stderr and exits 2 (no capture/redirect of the peer's +# output). set -uo pipefail