From Phone a Friend
Runs iterative multi-model refinement rounds across backends (Claude, Gemini, OpenCode, Ollama) with synthesis between rounds. Use when you want backends to critique each other and converge, not single relays.
How this skill is triggered — by the user, by Claude, or both
Slash command
/phone-a-friend:.codex <task description> [--backend <name>[,<name>,...]] [--max-rounds N] [--model <name>]<task description> [--backend <name>[,<name>,...]] [--max-rounds N] [--model <name>]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Iterative multi-model refinement loop. Use this when the user wants more than a single relay — they want backends to push back on each other across rounds and converge on something. For one-shot "ask X and Y" requests, use `/phone-a-friend` (which already supports parallel multi-backend) instead.
Iterative multi-model refinement loop. Use this when the user wants more than a single relay — they want backends to push back on each other across rounds and converge on something. For one-shot "ask X and Y" requests, use /phone-a-friend (which already supports parallel multi-backend) instead.
You orchestrate the rounds yourself via Bash. Do not spawn Codex subagents for this — the skill is designed to run end-to-end in the parent turn. Codex's own model does the synthesis between rounds by reading the per-backend outputs you write to disk.
$ARGUMENTS contains the user's request. Parse:
--backend <name> (or --backend a,b): comma-separated list of friend backends to query each round. Allowed: claude, gemini, opencode, ollama. Never codex (the recursion guard refuses; you would be calling yourself). Default: claude,gemini.--max-rounds N: rounds before giving up. Clamp to [1, 5]. Default: 3.--model <name>: only meaningful for ollama and opencode.If the user named only one backend, the team degenerates to a self-review loop against that backend across rounds. That is valid; do not error out, just proceed.
Resolve the binary. Always use the PATH-installed phone-a-friend, never ./phone-a-friend from the current directory.
RELAY_BIN="$(command -v phone-a-friend)"
if [ -z "$RELAY_BIN" ]; then
echo "phone-a-friend binary not on PATH. Install with: npm i -g @freibergergarcia/phone-a-friend" >&2
exit 1
fi
Resolve the repository path.
REPO="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
Check the Codex sandbox mode. You are running inside Codex. By default, Codex uses workspace-write, which blocks subprocess access to the macOS Keychain and most outbound network. That means relays to Claude will return Not logged in · Please run /login (false alarm — Claude is logged in; the sandbox is intercepting) and relays to Gemini will hang until the timeout fires (Gemini cannot reach Google for OAuth refresh).
Before starting round 1, tell the user:
/phone-a-team will spawn parallel relays to ${BACKENDS}. Codex's default sandbox blocks the keychain and OAuth refresh paths these CLIs need. For best results, restart Codex with
codex --sandbox danger-full-access(or--full-auto). Alternatively, exportANTHROPIC_API_KEY/GEMINI_API_KEY/OPENAI_API_KEYin your shell before launching Codex — the API-key path skips OAuth entirely.
If the user has already opened up the sandbox (or set the API keys), proceed. Otherwise it is reasonable to abort the team run upfront — running it would either burn the per-round timeout on every backend (Gemini hang) or surface a misleading "Not logged in" (Claude). Both are bad UX.
Stable across rounds so the friend backends resume their prior context per round instead of re-receiving the full task description every time.
TASK_SLUG="$(echo "$TASK_DESCRIPTION" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9 ]//g' | awk '{print $1"-"$2"-"$3}')"
RAND4="$(head -c 16 /dev/urandom | xxd -p | head -c 4)"
TEAM_ID="paf-team-${TASK_SLUG}-${RAND4}"
For each backend in the comma-separated list, the session label is ${TEAM_ID}-<backend>. Reuse that exact label across every round so the backend continues its thread.
| Backend | resumeStrategy | Pass --session? |
|---|---|---|
| claude | native-session | yes |
| codex | native-session | yes (never used here; recursion guard) |
| opencode | native-session | yes |
| ollama | transcript-replay | yes |
| gemini | native-session | yes |
Build the relay flag accordingly per backend:
session_flag_for() {
local b="$1"
echo "--session ${TEAM_ID}-${b}"
}
Write the round prompt to a temp file, then fan out to every backend in the background.
ROUND_DIR="$(mktemp -d)"
trap 'rm -rf "$ROUND_DIR"' EXIT
ROUND=1
ROUND_PROMPT="$ROUND_DIR/r${ROUND}-prompt.txt"
cat > "$ROUND_PROMPT" <<'PAF_TEAM_EOF'
You are one member of a small panel reviewing this task. Be specific and actionable. Push back where you disagree with assumptions; flag risks even if they are not blockers. If you have nothing to add, say so directly rather than padding.
Task:
${TASK_DESCRIPTION}
PAF_TEAM_EOF
for BACKEND in $(echo "$BACKENDS" | tr ',' ' '); do
PHONE_A_FRIEND_HOST=codex PHONE_A_FRIEND_INCLUDE_DIFF=false \
"$RELAY_BIN" --to "$BACKEND" --repo "$REPO" \
--prompt "$(cat "$ROUND_PROMPT")" \
$(session_flag_for "$BACKEND") \
--timeout 180 --no-stream --no-include-diff \
> "$ROUND_DIR/r${ROUND}-${BACKEND}.out" 2> "$ROUND_DIR/r${ROUND}-${BACKEND}.err" &
done
wait
Use single-quoted heredocs (<<'PAF_TEAM_EOF') so user-supplied text cannot break shell quoting. Substitute ${TASK_DESCRIPTION} from your shell env before writing the file (the safer pattern is printf + sed to assemble the file rather than relying on heredoc expansion).
--timeout 180 is a per-round upper bound. A 3-minute hang is generous for a single relay; if a backend has not produced anything in that window it is functionally stalled. Adjust upward only when the task genuinely takes longer (e.g., a deep code review).
Read every r${ROUND}-${BACKEND}.out file. You (the Codex model running this skill) produce the synthesis directly in your next response. Do not shell out for this; you already have all the context.
Synthesis shape:
### Round ${ROUND} synthesis
**Convergence**: one paragraph naming points the backends agree on.
**Divergence**: one paragraph naming where they disagreed (and which backend said which side).
**Unresolved**: bulleted list of concrete questions or risks still open.
**Verdict**: one of SHIP, ITERATE, ABSTAIN.
- SHIP: backends converged, no blockers, no further iteration needed.
- ITERATE: at least one important point unresolved; another round may help.
- ABSTAIN: no backend produced actionable content (auth failures, timeouts, refusals). Stop and tell the user.
If a backend's .err file is non-empty (auth failure, timeout, refusal), include that in the synthesis verbatim — do not silently drop the backend. Cap the synthesis at ~200 words; the user reads it.
| Verdict | Round count | Action |
|---|---|---|
| SHIP | any | Stop. Final output is the round-N synthesis plus the strongest verbatim quote from the converging backends. |
| ABSTAIN | any | Stop. Surface what failed so the user can fix it (re-auth, network, etc.). |
| ITERATE | < MAX | Build the round-N+1 prompt: a short "here is the panel's synthesis of round N; refine your prior reply" delta. Same parallel-fan-out pattern, same session labels (the backends resume their thread, so only the delta is needed). |
| ITERATE | = MAX | Stop. Report that the team hit the round cap without convergence; include the final synthesis so the user sees the state. |
Round N+1 prompt template:
NEXT=$((ROUND + 1))
DELTA_PROMPT="$ROUND_DIR/r${NEXT}-prompt.txt"
cat > "$DELTA_PROMPT" <<'PAF_TEAM_EOF'
Round ${NEXT}. Below is the panel's synthesis of the previous round. Refine your prior response: keep what holds, change what does not. If you stand by your prior position, say so explicitly and explain why.
${SYNTHESIS_TEXT}
PAF_TEAM_EOF
Then re-run the parallel relay block from Step 2 with ROUND=$NEXT and the new prompt file. Session labels are unchanged.
Show the user:
| Backend | Final answer | Status |
|---|---|---|
| Claude | <one-line summary> | converged |
| Gemini | <one-line summary> | converged |
phone-a-friend session list / session prune.--to codex. The recursion guard refuses, and you would be calling yourself.$RELAY_BIN from command -v phone-a-friend. Never ./phone-a-friend.--timeout 180. Do not omit the timeout flag; a single hung backend should not block the team.& + wait). Never sequentially.PHONE_A_FRIEND_HOST=codex and PHONE_A_FRIEND_INCLUDE_DIFF=false on every relay invocation so the recursion marker is set and diffs are suppressed by default.Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub freibergergarcia/phone-a-friend