sync: auto-sync from GURU-5070 at 2026-06-04 07:59:53
Author: Mike Swanson Machine: GURU-5070 Timestamp: 2026-06-04 07:59:53
This commit is contained in:
@@ -75,6 +75,27 @@ else
|
||||
echo " Prose model: qwen3:14b (default)"
|
||||
fi
|
||||
|
||||
# Detect Grok CLI (xAI) — optional capability extension (image/video, live web+X
|
||||
# data, independent second model). Per-machine; sets identity grok.installed so
|
||||
# the /grok skill knows whether it can run locally. Does NOT set is_fleet_host
|
||||
# (that's a manual fleet-coordination choice, preserved if already present).
|
||||
GROK_BIN=""
|
||||
if command -v grok >/dev/null 2>&1; then
|
||||
GROK_BIN="$(command -v grok)"
|
||||
else
|
||||
for c in "$HOME/.grok/bin/grok.exe" "$HOME/.grok/bin/grok" "${LOCALAPPDATA:-}/Programs/grok/grok.exe"; do
|
||||
if [ -x "$c" ]; then GROK_BIN="$c"; break; fi
|
||||
done
|
||||
fi
|
||||
if [ -n "$GROK_BIN" ]; then
|
||||
GROK_BIN="$(cygpath -m "$GROK_BIN" 2>/dev/null || echo "$GROK_BIN")"
|
||||
GROK_INSTALLED="true"
|
||||
echo " Grok: installed ($GROK_BIN)"
|
||||
else
|
||||
GROK_INSTALLED="false"
|
||||
echo " Grok: not installed"
|
||||
fi
|
||||
|
||||
# Build updated identity.json
|
||||
echo ""
|
||||
echo "[INFO] Updating identity.json..."
|
||||
@@ -104,6 +125,17 @@ if 'platform' not in data:
|
||||
if 'architecture' not in data:
|
||||
data['architecture'] = '$ARCH'
|
||||
|
||||
# Grok capability flag (per-machine). Preserve manual keys like is_fleet_host.
|
||||
g = data.get('grok') or {}
|
||||
if '$GROK_INSTALLED' == 'true':
|
||||
g['installed'] = True
|
||||
g['binary'] = r'$GROK_BIN'
|
||||
g.setdefault('auth', 'oidc')
|
||||
g.setdefault('capabilities', ['text', 'verify', 'image', 'video', 'xsearch'])
|
||||
else:
|
||||
g['installed'] = False
|
||||
data['grok'] = g
|
||||
|
||||
# Coord API endpoint — populate only if absent so existing machines keep their override.
|
||||
if 'coord_api' not in data:
|
||||
data['coord_api'] = '$COORD_API_DEFAULT'
|
||||
@@ -125,6 +157,7 @@ echo " ollama.fallback: $OLLAMA_FALLBACK"
|
||||
echo " ollama.prose_model: $PROSE_MODEL"
|
||||
echo " platform: $PLATFORM"
|
||||
echo " architecture: $ARCH"
|
||||
echo " grok.installed: $GROK_INSTALLED"
|
||||
echo " coord_api: (default $COORD_API_DEFAULT if not already set)"
|
||||
echo ""
|
||||
echo "Review: cat $IDENTITY_PATH"
|
||||
|
||||
88
.claude/skills/grok/SKILL.md
Normal file
88
.claude/skills/grok/SKILL.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: grok
|
||||
description: >
|
||||
Route a task to the Grok CLI (xAI Grok 4.3) for capabilities Claude lacks or
|
||||
for an independent second model. Use for: IMAGE generation/editing, VIDEO
|
||||
generation (image->video), live WEB + X/TWITTER search (current/real-time
|
||||
data past Claude's cutoff), and adversarial second-opinion VERIFICATION or
|
||||
drafts. Invoke on: "ask grok", "grok image", "generate/make an image",
|
||||
"make a video / animate this", "grok verify / second opinion from grok",
|
||||
"search X / twitter", "what's the latest <current-event/version>". Grok is a
|
||||
capability EXTENSION (image/video/live-data), not a replacement for Claude's
|
||||
own coding/editing.
|
||||
---
|
||||
|
||||
# Grok capability router
|
||||
|
||||
Claude shells out to the locally-installed **Grok CLI** (`grok.exe`, xAI Grok 4.3)
|
||||
for things Claude can't do natively, or for a genuinely independent second model.
|
||||
Verified working on this machine (2026-06-04): image gen, image->video, live
|
||||
web/X search, text reasoning.
|
||||
|
||||
**Auth:** Grok uses its own OIDC login (`~/.grok/auth.json`, grok.com, ~6h refresh)
|
||||
— **no API key**. If calls fail with auth errors, the user runs `grok login`.
|
||||
|
||||
## The wrapper
|
||||
|
||||
```
|
||||
bash "$CLAUDETOOLS_ROOT/.claude/skills/grok/scripts/ask-grok.sh" <mode> ...
|
||||
```
|
||||
|
||||
| Mode | Usage | What it does |
|
||||
|------|-------|--------------|
|
||||
| `text` | `ask-grok.sh text "<prompt>"` | One-shot text answer (independent model). Prints to stdout. |
|
||||
| `verify` | `ask-grok.sh verify "<claim/finding>"` | Adversarial second opinion — Grok tries to REFUTE, returns CONFIRMED/REFUTED + reason. |
|
||||
| `image` | `ask-grok.sh image "<prompt>" [out.png]` | `image_gen` (Imagine) → copies the artifact to `out` (default `grok-image.png`). |
|
||||
| `video` | `ask-grok.sh video "<motion prompt>" <input-image> [out.mp4]` | `image_to_video` on an input image → copies to `out`. ~60-90s. |
|
||||
| `xsearch` | `ask-grok.sh xsearch "<query>"` | Live `web_search` + X/Twitter tools; returns text with citations. |
|
||||
| `raw` | `ask-grok.sh raw <grok args...>` | Escape hatch — passes args straight to `grok`. |
|
||||
|
||||
The script captures JSON (`--output-format json`), parses the result, and for
|
||||
media **retrieves the artifact by sessionId** from
|
||||
`~/.grok/sessions/<enc-cwd>/<sessionId>/{images,videos}/` — so artifacts are
|
||||
recovered even when a headless run reports `stopReason: Cancelled` before echoing
|
||||
the path (a known finalization quirk of the `-p` mode).
|
||||
|
||||
## Machine availability (fleet)
|
||||
|
||||
Grok is **per-machine** — the skill syncs fleet-wide but the binary does not. Availability is gated by `identity.json` (per-machine, gitignored):
|
||||
|
||||
```json
|
||||
"grok": { "installed": true, "binary": "C:/Users/guru/.grok/bin/grok.exe",
|
||||
"auth": "oidc", "is_fleet_host": true,
|
||||
"capabilities": ["text","verify","image","video","xsearch"] }
|
||||
```
|
||||
|
||||
- If `grok.installed` is `false` (or the block is absent), `ask-grok.sh` exits **3** with routing guidance instead of failing obscurely. Claude on such a machine should NOT attempt local Grok.
|
||||
- **Current fleet Grok host: `GURU-5070`** — the only machine with Grok installed right now. When others get it, set their `identity.json` `grok` block (and update this line).
|
||||
|
||||
**Remote routing (NOT yet wired):** a non-host machine cannot run Grok locally. To fulfill a Grok request from elsewhere, route it to the host (`GURU-5070`). Candidate channels: GuruRMM agent command execution (`/rmm` — GURU-5070 is enrolled; the hard part is shipping image/video artifacts back), `grok agent serve` (WebSocket relay), or a coord-API job queue. Until that's built, Grok requests originate on the host machine.
|
||||
|
||||
## When to route to Grok
|
||||
|
||||
- **Image / video creation or editing** — Claude can't generate media; Grok can. (`image`, `video`)
|
||||
- **Current / real-time facts** — anything past Claude's knowledge cutoff, breaking news, latest versions, or X/Twitter sentiment. (`xsearch`)
|
||||
- **Independent verification** — a genuinely different vendor/model to red-team a Claude finding or design before acting on it. (`verify`)
|
||||
- **Diverse drafts / second opinion** — alternative phrasing or approach to compare. (`text`)
|
||||
|
||||
## When NOT to
|
||||
|
||||
- Pure classify/extract/summarize → cheaper via Tier-0 Ollama (`.claude/OLLAMA.md`).
|
||||
- Editing this repo's code → Claude's own agents (the Grok CLI *can* read `.claude/` and run tools, but Claude owns the codebase work).
|
||||
- **Never** delegate unsupervised destructive / production actions to Grok. The
|
||||
earlier SBS post-mortem (`docs/session-notes/2026-06-03-claude-postmortem-grok-mspbackups-sbs.md`)
|
||||
showed Grok over-claims and under-verifies — **always review Grok output before
|
||||
acting on it**, and confirm media is what was asked for (Claude can view images).
|
||||
|
||||
## Safety / operational notes
|
||||
|
||||
- `~/.grok/config.toml` defaults to `permission_mode = "always-approve"` (auto-runs tools). The wrapper overrides with `--permission-mode dontAsk` and `--no-subagents`; do not bypass that.
|
||||
- Prompts are passed via `--prompt-file` only (inline args break on shell quoting).
|
||||
- `grok-build` rejects `--effort`/`--reasoning-effort` (400) — don't pass them.
|
||||
- Models available: `grok-build` (default), `grok-composer-2.5-fast`. The agent self-reports as Grok 4.3.
|
||||
- After media gen, Claude should **view the image** (Read tool) to confirm correctness; videos can be confirmed by header/ffprobe.
|
||||
|
||||
## Reference
|
||||
- Binary: `~/.grok/bin/grok.exe` (not on PATH; the wrapper auto-locates it or honors `GROK=`).
|
||||
- Full capability investigation + verification: see the 2026-06-04 session log.
|
||||
- Grok native tools observed: `image_gen`, `image_edit`, `image_to_video`, `reference_to_video`, `web_search`, `web_fetch`, `x_keyword_search`, `x_semantic_search`, `x_user_search`, `x_thread_fetch`, `run_terminal_command`, file ops, `scheduler_*`, `monitor`, memory.
|
||||
144
.claude/skills/grok/scripts/ask-grok.sh
Normal file
144
.claude/skills/grok/scripts/ask-grok.sh
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
# ask-grok.sh — Claude -> Grok capability router.
|
||||
#
|
||||
# Routes a task to the Grok CLI (xAI Grok 4.3) for capabilities Claude lacks
|
||||
# (image/video generation, live web + X/Twitter data) or for an independent
|
||||
# second model (verification, drafts). Headless, safe-by-default, artifact-aware.
|
||||
#
|
||||
# Auth is Grok's own OIDC (~/.grok/auth.json, grok.com login) — NO API key here.
|
||||
# Prompts are ALWAYS passed via --prompt-file (inline args break on shell quoting).
|
||||
# Artifacts (image/video) are retrieved by globbing the session dir by sessionId,
|
||||
# so they're recovered even when the headless run reports stopReason=Cancelled
|
||||
# before echoing the path (a known finalization quirk).
|
||||
#
|
||||
# Usage:
|
||||
# ask-grok.sh text "<prompt>" # text / reasoning / second opinion
|
||||
# ask-grok.sh verify "<claim or finding to refute>" # adversarial check (text + --check)
|
||||
# ask-grok.sh image "<prompt>" [out.png] # image_gen -> copy artifact to out
|
||||
# ask-grok.sh video "<prompt>" <input-image> [out.mp4] # image_to_video on input image
|
||||
# ask-grok.sh xsearch "<query>" # live X/Twitter + web search
|
||||
# ask-grok.sh raw <grok args...> # escape hatch (passes through)
|
||||
#
|
||||
# Exit: 0 ok, 1 no result/artifact, 2 usage, 127 grok not found.
|
||||
set -uo pipefail
|
||||
SELF="ask-grok"
|
||||
|
||||
PY="$(command -v py 2>/dev/null || command -v python 2>/dev/null || command -v python3 2>/dev/null || true)"
|
||||
[ -z "$PY" ] && { echo "[$SELF] python (py/python/python3) required for JSON parsing" >&2; exit 127; }
|
||||
|
||||
# --- identity.json (per-machine, gitignored) declares whether grok is installed here ---
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd)"
|
||||
IDFILE=""
|
||||
[ -n "${CLAUDETOOLS_ROOT:-}" ] && [ -f "$CLAUDETOOLS_ROOT/.claude/identity.json" ] && IDFILE="$CLAUDETOOLS_ROOT/.claude/identity.json"
|
||||
[ -z "$IDFILE" ] && IDFILE="$(cd "$SCRIPT_DIR/../../.." 2>/dev/null && pwd)/identity.json"
|
||||
idgrok() { # read field $1 from identity.json .grok (empty if absent)
|
||||
[ -f "$IDFILE" ] || { echo ""; return; }
|
||||
"$PY" -c "import json,sys
|
||||
try:
|
||||
g=(json.load(sys.stdin).get('grok') or {}); v=g.get('$1','')
|
||||
print('' if v is None else (str(v).lower() if isinstance(v,bool) else v))
|
||||
except Exception: print('')" < "$IDFILE"
|
||||
}
|
||||
|
||||
# If identity explicitly says grok is NOT installed here, fail fast with routing guidance.
|
||||
if [ "$(idgrok installed)" = "false" ]; then
|
||||
echo "[$SELF] grok is not installed on this machine (identity.json grok.installed=false)." >&2
|
||||
echo "[$SELF] Grok runs only on the fleet grok host. Route this request there (remote routing not yet wired) or install grok + set identity.json grok.installed=true." >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# --- locate the grok binary: GROK env > identity.json grok.binary > auto-locate ---
|
||||
GROK="${GROK:-}"
|
||||
cand="$(idgrok binary)"
|
||||
[ -z "$GROK" ] && [ -n "$cand" ] && [ -x "$cand" ] && GROK="$cand"
|
||||
if [ -z "$GROK" ]; then
|
||||
if command -v grok >/dev/null 2>&1; then GROK="$(command -v grok)"; else
|
||||
for c in "$HOME/.grok/bin/grok.exe" "/c/Users/${USERNAME:-${USER:-x}}/.grok/bin/grok.exe" \
|
||||
"$HOME/.grok/bin/grok" "${LOCALAPPDATA:-}/Programs/grok/grok.exe"; do
|
||||
[ -x "$c" ] && { GROK="$c"; break; }
|
||||
done
|
||||
fi
|
||||
fi
|
||||
[ -z "$GROK" ] && { echo "[$SELF] grok CLI not found (set identity.json grok.binary, GROK=, or install grok)" >&2; exit 127; }
|
||||
|
||||
MODE="${1:-}"; shift 2>/dev/null || true
|
||||
[ -z "$MODE" ] && { echo "usage: $SELF {text|verify|image|video|xsearch|raw} ..." >&2; exit 2; }
|
||||
|
||||
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
|
||||
WORK="$TMP/work"; mkdir -p "$WORK"
|
||||
PF="$TMP/prompt.txt"; OUT="$TMP/out.json"
|
||||
|
||||
# run grok headless. $1=timeout secs; rest=extra flags. Reads $PF -> $OUT.
|
||||
# Never fails the script on grok's exit code (Cancelled is expected; we read artifacts).
|
||||
run_grok() {
|
||||
local to="$1"; shift
|
||||
timeout "$to" "$GROK" --prompt-file "$PF" --output-format json \
|
||||
--permission-mode dontAsk --no-subagents --no-plan --cwd "$WORK" "$@" \
|
||||
>"$OUT" 2>"$TMP/err.txt" || true
|
||||
}
|
||||
|
||||
# parse a top-level field from $OUT. Read via stdin so Windows python never has
|
||||
# to resolve the git-bash (/c/...) path itself.
|
||||
jfield() { "$PY" -c "import json,sys
|
||||
try:
|
||||
d=json.load(sys.stdin); print(d.get('$1','') or '')
|
||||
except Exception:
|
||||
print('')" < "$OUT"; }
|
||||
|
||||
# newest artifact under any session dir for this sessionId: $1=sid $2=images|videos
|
||||
find_artifact() {
|
||||
ls -t "$HOME/.grok/sessions/"*"/$1/$2/"* 2>/dev/null | head -1
|
||||
}
|
||||
|
||||
case "$MODE" in
|
||||
text|verify)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF $MODE \"<prompt>\"" >&2; exit 2; }
|
||||
# Prompt-level steering keeps it text-only and (for verify) adversarial.
|
||||
# (The --disallowed-tools/--rules flags tripped the CLI; --check adds a slow
|
||||
# multi-turn self-check loop — both avoided in favor of prompt steering.)
|
||||
if [ "$MODE" = "verify" ]; then
|
||||
printf 'Adversarially evaluate the following claim/finding: try hard to find any reason it is WRONG. Then give a one-line verdict (CONFIRMED or REFUTED) plus a one-sentence justification. Answer in text only; do not use tools. Claim/finding: %s' "$1" > "$PF"
|
||||
else
|
||||
printf 'Answer directly in text; do not use tools. %s' "$1" > "$PF"
|
||||
fi
|
||||
run_grok 120 --disable-web-search --max-turns 2
|
||||
txt="$(jfield text)"
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no text (stopReason=$(jfield stopReason)); raw: $OUT" >&2; exit 1; fi
|
||||
;;
|
||||
image)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF image \"<prompt>\" [out.png]" >&2; exit 2; }
|
||||
out="${2:-grok-image.png}"
|
||||
printf 'Use your image_gen tool to generate exactly this image, save it, then stop. Image: %s' "$1" > "$PF"
|
||||
run_grok 240 --disable-web-search --max-turns 12
|
||||
sid="$(jfield sessionId)"; art="$(find_artifact "$sid" images)"
|
||||
if [ -n "$art" ] && [ -f "$art" ]; then cp -f "$art" "$out"
|
||||
echo "[$SELF] image OK -> $out (session $sid)"
|
||||
else echo "[$SELF] no image artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
;;
|
||||
video)
|
||||
[ -z "${1:-}" ] || [ -z "${2:-}" ] && { echo "usage: $SELF video \"<prompt>\" <input-image> [out.mp4]" >&2; exit 2; }
|
||||
input="$2"; out="${3:-grok-video.mp4}"
|
||||
[ -f "$input" ] || { echo "[$SELF] input image not found: $input" >&2; exit 2; }
|
||||
cp -f "$input" "$WORK/input.jpg"
|
||||
printf 'Use your image_to_video tool to animate input.jpg (in the current directory) into a short clip, save it, then stop. Motion: %s' "$1" > "$PF"
|
||||
run_grok 360 --disable-web-search --max-turns 20
|
||||
sid="$(jfield sessionId)"; art="$(find_artifact "$sid" videos)"
|
||||
if [ -n "$art" ] && [ -f "$art" ]; then cp -f "$art" "$out"
|
||||
echo "[$SELF] video OK -> $out (session $sid)"
|
||||
else echo "[$SELF] no video artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
;;
|
||||
xsearch)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF xsearch \"<query>\"" >&2; exit 2; }
|
||||
printf 'Use your web_search and X/Twitter search tools to answer this, cite sources, then stop: %s' "$1" > "$PF"
|
||||
run_grok 150 --max-turns 6
|
||||
txt="$(jfield text)"
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no result (stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
;;
|
||||
raw)
|
||||
"$GROK" "$@"
|
||||
;;
|
||||
*)
|
||||
echo "[$SELF] unknown mode '$MODE' (use text|verify|image|video|xsearch|raw)" >&2; exit 2 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user