Council Members
5
Consensus Model
Gemma3:27b
Streaming
SSE
Access
Tailnet
01 — The Problem

Single Models Have Single Blind Spots

Any one LLM can hallucinate, miss perspectives, or get stuck in a reasoning rut. The fix isn't a bigger model — it's a council of smaller ones, each with a distinct role, queried in parallel, then synthesized. Multiple training backgrounds plus role-specific system prompts produces answers that are cross-validated by construction, not by hope.

Diversity
Five Perspectives, Not One
Each council member has a distinct role — comprehensive analysis, quick insight, critical pushback, historical context, strategic planning. Different models, different priors, the same question.
Synthesis
Consensus Engine
Gemma3:27b reads all five responses and writes a unified answer that reconciles agreements, surfaces tensions, and notes where the council disagrees.
Distributed
Models Spread Across the Lab
Two Ollama hosts share the load — the inference box at adi-cortex runs the larger models, a secondary host carries the lighter ones. Nothing leaves the tailnet.
Streaming
SSE All The Way Down
Every response streams token-by-token via Server-Sent Events. The user sees thinking happen rather than waiting for a wall of text to land at once.
02 — The Council

Five Roles, Five Models

Each member is a distinct Ollama model with a role-specific system prompt. The role isn't just flavor — it shapes the prompt the model sees and the kind of answer the consensus engine has to weigh.

Primary Assistant
Gemma3:12b
Comprehensive, well-structured answers. The workhorse the rest of the council pushes against. Endpoint adi-cortex:11434.
Quick Insights
Qwen3:4b
Fast, concise responses that capture the essentials in seconds. Cuts through complexity without committee-speak. Endpoint adi-cortex:11434.
Critical Analysis
WizardLM2:7b
Questions assumptions, surfaces alternative viewpoints, names the failure modes the rest missed. The dissenting voice every council needs.
Historical Context
Phi3:3.8b
Relates the question to precedents, prior incidents, and long-running patterns. Stops the council from rediscovering wheels.
Strategy & Foresight
GPT-OSS:20b
Turns problems into executable plans — numbered steps, assumptions, verification checks, rollback paths. Prefers commands and exact paths over prose.
Synthesis
Gemma3:27b
Not a council member — the consensus engine. Reads the five responses and writes a single unified answer. The largest model in the stack on purpose.
03 — Architecture

Browser → Proxy → Ollama → Consensus

A PHP proxy sits between the browser and Ollama. The browser doesn't know about model endpoints — it sends a prompt, the proxy fans out to all five members, streams every response back, then calls the consensus endpoint when the council is done.

Browser UI ollama_proxy.php Routes to Ollama instances adi-cortex:11434 GM3 QW WL secondary host:11434 PH3 GPT consensus.php Gemma3:27b synthesis
Council architecture
04 — Response Modes

Sequential or Parallel

Two modes selectable from a dropdown. Sequential reads like a conversation; parallel reads like a brief. Same models, same prompts, different feel.

Mode 01
Sequential
Members respond one at a time, in order. Each answer streams with a typing cursor before the next member starts. Good for following the chain of reasoning — you can see when the historian flags a precedent the assistant missed.
Mode 02
Parallel
All five members queried at once via Promise.all(). Each response streams independently into its own panel; total time drops to the slowest model. Use when you want answers, not theatre.
05 — Role Prompts

The Role Lives in the Prompt

Each member receives a role-specific system prompt before the user's question. The prompt is what makes the historian historical and the strategist strategic — the model itself is unaware of the council.

JavaScript
const rolePrompts = {
  adi: `You are Gemma3, the primary AI assistant. Provide
        comprehensive, well-structured responses with clear
        explanations and examples when helpful.`,

  qwen: `You are Qwen3, focused on quick, concise insights.
         Give clear, direct answers that capture the key
         points efficiently.`,

  wizardlm: `You are WizardLM, the critical analyst. Question
             assumptions, present alternative viewpoints, and
             provide constructive criticism.`,

  historian: `You are Phi3, specializing in historical context.
              Relate topics to historical precedents and trends.`,

  strategos: `You are GPT-OSS STRATEGOS, the Council's staff
              planner. Turn problems into clear, executable plans
              with assumptions, numbered steps, verification
              checks, rollback paths, and risks. Prefer commands,
              exact paths, and short rationale.`
};
06 — Stack

What It's Built On

PHP procedural, no frameworks. Streaming over Server-Sent Events — curl on the server side, EventSource on the browser side. Tailscale for access control. Apache binds only to the tailnet interface.

Application
PHP 8 · Procedural
Three files do the work: index.php for the UI, ollama_proxy.php for streaming, consensus.php for synthesis. No frameworks, no ORM.
Inference
Ollama · Local Only
Heavier models run on the dual-5060 Ti box at adi-cortex; a secondary host carries the smaller ones. Models swap by editing the COUNCIL_MEMBERS array.
Streaming
Server-Sent Events
PHP-side curl with WRITEFUNCTION + ob_flush() to push tokens as they arrive. Browser reads with EventSource. Stream ends with a sentinel [STREAM_END].
Tailnet-Only
No Public Ingress
Apache binds to the Tailscale interface. The proxy talks to Ollama over the same tailnet. The wider internet sees nothing.
07 — Proxy

The Streaming Proxy

All council traffic goes through one PHP file. The browser never talks to Ollama directly — that keeps endpoints, model names, and the tailnet topology server-side.

PHP
<?php
// ollama_proxy.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$input    = json_decode(file_get_contents('php://input'), true);
$endpoint = $input['endpoint'] ?? 'adi-cortex';
$model    = $input['model']    ?? 'gemma3:12b';
$prompt   = $input['prompt']   ?? '';

$payload = json_encode([
    'model'  => $model,
    'prompt' => $prompt,
    'stream' => true
]);

$ch = curl_init("http://{$endpoint}:11434/api/generate");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) {
    echo $data;
    ob_flush();
    flush();
    return strlen($data);
});
curl_exec($ch);
echo '[STREAM_END]';
curl_close($ch);
08 — Source

Get the Code

Three files plus a config block. Drop on a LAMP stack with Ollama reachable over the network, edit the COUNCIL_MEMBERS array to match your hosts, and it runs.

v2026.05 · council
AI Council

PHP proxy, consensus engine, and browser UI — the same code currently running on the lab's tailnet against adi-cortex.

Download ZIP
PHP 8 · Apache 2.4 · Ollama (local or networked)