Skill: jeadland/ask-council (version 1.0.4)

--- name: ask-council version: 1.0.3 description: | Ask LLM Council a question directly from Telegram/chat — get the chairman's synthesized answer without opening the web UI. Quick, headless access to multi-model consensus. slash_command: /council metadata: {"category":"productivity","tags":["llm","council","quick","telegram","cli"],"repo":"https://github.com/jeadland/llm-council"} --- # Ask Council — Quick Headless Access Get LLM Council's synthesized answer without leaving your chat. ## Usage ``` /council Should I invest in Tesla right now? ``` Returns the **Chairman's synthesized answer** after all models have debated. ## How It Works 1. Sends your question to the LLM Council backend 2. Waits for Stage 1 (all models respond) 3. Waits for Stage 2 (models rank each other) 4. Returns Stage 3 (Chairman's final synthesis) **Takes 30-60 seconds** — models need time to deliberate. ## Prerequisites LLM Council backend must be running: ``` /install-llm-council ``` ## Two Ways to Use LLM Council | Mode | Best For | Command | |------|----------|---------| | **Quick answer** (this skill) | Fast decisions, mobile, casual questions | `/council "question"` | | **Full discussion** (web UI) | Deep research, exploring disagreements, seeing all model responses | `/install-llm-council` then open browser | ## Example **Input:** ``` /council Is Python or Go better for a new microservice? ``` **Output:** ``` Council is deliberating... (this may take 30-60s) ................ ═══════════════════════════════════════════════════════════════ CHAIRMAN'S ANSWER ═══════════════════════════════════════════════════════════════ Based on the council's deliberation, Python is recommended for rapid prototyping and team velocity, while Go excels for high-throughput services where performance is critical... ═══════════════════════════════════════════════════════════════ View full discussion: http://10.0.1.184:5173 ``` ## Agent Instructions When user says `/council <question>` or "ask council": ```bash bash ~/.openclaw/skills/ask-council/ask-council.sh "<question>" ``` The script handles: - Creating a conversation - Starting the council run - Polling until complete - Extracting the chairman's answer - Showing progress dots while waiting ## Files | File | Purpose | |------|---------| | `SKILL.md` | Documentation | | `ask-council.sh` | Main script — queries API and returns answer | | `_meta.json` | Skill metadata | ## Notes - Timeout: 120 seconds - If backend isn't running, suggests starting it - Always includes link to full web UI for detailed exploration - Creates a new conversation each time (no history)

path: _meta.json
content: slug: ask-council
version: 1.0.3

path: ask-council.sh
content: #!/usr/bin/env bash
# ask-council — Quick headless access to LLM Council
# Usage: bash ask-council.sh "Your question here"
#
# Returns: Chairman's synthesized answer (or error message)

set -euo pipefail

API_BASE="http://127.0.0.1:8001"
TIMEOUT_SEC=120

# ── Colors ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
error() { echo -e "${RED}[ask-council]${NC} $*" >&2; exit 1; }
info()  { echo -e "${GREEN}[ask-council]${NC} $*"; }
warn()  { echo -e "${YELLOW}[ask-council]${NC} $*"; }

# ── Check input ───────────────────────────────────────────────────────────────
QUESTION="${1:-}"
if [[ -z "$QUESTION" ]]; then
  error "Usage: ask-council.sh 'Your question here'"
fi

# ── Check if backend is running ───────────────────────────────────────────────
if ! curl -s "$API_BASE/" > /dev/null 2>&1; then
  error "LLM Council backend not running. Start it first:\n  /install-llm-council"
fi

# ── Create conversation ───────────────────────────────────────────────────────
CONVO_RESPONSE=$(curl -s -X POST "$API_BASE/api/conversations" -H "Content-Type: application/json" -d '{}')
CONVO_ID=$(echo "$CONVO_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin)['id'])")
SHORT_ID=$(echo "$CONVO_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('short_id', ''))")
if [[ -z "$CONVO_ID" ]]; then
  error "Failed to create conversation"
fi

# ── Start council run ─────────────────────────────────────────────────────────
RUN_RESPONSE=$(curl -s -X POST "$API_BASE/api/conversations/$CONVO_ID/runs" \
  -H "Content-Type: application/json" \
  -d "{\"content\": $(echo "$QUESTION" | python3 -c 'import json, sys; print(json.dumps(sys.stdin.read().strip()))')}")
RUN_ID=$(echo "$RUN_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin)['run_id'])")
if [[ -z "$RUN_ID" ]]; then
  error "Failed to start council run"
fi

info "Council is deliberating... (this may take 30-60s)"

# ── Poll until complete ───────────────────────────────────────────────────────
START_TIME=$(date +%s)
while true; do
  NOW=$(date +%s)
  ELAPSED=$((NOW - START_TIME))
  
  if [[ $ELAPSED -gt $TIMEOUT_SEC ]]; then
    error "Timed out after ${TIMEOUT_SEC}s. The council is still talking."
  fi

  STATUS=$(curl -s "$API_BASE/api/conversations/$CONVO_ID/runs/$RUN_ID")
  RUN_STATE=$(echo "$STATUS" | python3 -c "import sys, json; print(json.load(sys.stdin).get('status', 'unknown'))")
  
  case "$RUN_STATE" in
    complete)
      break
      ;;
    failed|canceled)
      ERROR=$(echo "$STATUS" | python3 -c "import sys, json; print(json.load(sys.stdin).get('error', 'Unknown error'))")
      error "Council session failed: $ERROR"
      ;;
    *)
      sleep 2
      echo -n "."
      ;;
  esac
done

echo ""  # newline after dots

# ── Extract chairman answer ───────────────────────────────────────────────────
CHAIRMAN_ANSWER=$(echo "$STATUS" | python3 -c "
import sys, json
data = json.load(sys.stdin)
stage3 = data.get('stage3', {})
if stage3.get('status') == 'complete':
    result = stage3.get('data', {})
    print(result.get('response', 'No answer found'))
else:
    print('Chairman did not complete synthesis')
")

# ── Output ────────────────────────────────────────────────────────────────────
LOCAL_IP="$(hostname -I | awk '{print $1}')"

echo ""
echo "═══════════════════════════════════════════════════════════════"
echo "                    CHAIRMAN'S ANSWER"
echo "═══════════════════════════════════════════════════════════════"
echo ""
echo "$CHAIRMAN_ANSWER"
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo ""
if [[ -n "$SHORT_ID" ]]; then
  echo "Short ID: $SHORT_ID"
  echo ""
  echo "View full discussion: http://${LOCAL_IP}:5173/c/${SHORT_ID}"
else
  echo "Conversation ID: $CONVO_ID"
  echo ""
  echo "View full discussion: http://${LOCAL_IP}:5173"
fi
echo ""


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)