Ask one important question. Several frontier models deliberate. You get either a free-form council debate or an auditable, citation-backed brief.
Built for Mesh Hack 2026. All inference routes through Mesh API.
Sample chats:
Setup, env vars, deploy, and tests live in setup.md.
Agents should start with AGENT.README.md.
Single-model answers hide disagreement, brand bias, and unsupported claims. AI RoundTable turns one question into a multi-model council:
- Pick 2–5 models and how many rounds they get.
- Models answer independently, then debate or critique.
- A fixed organizer model synthesizes the result.
- You inspect the transcript, not just the final paragraph.
Two modes, chosen before the chat starts and never mixed:
| Mode | What you get |
|---|---|
| Regular | Free-form debate under real model names, then a short council conclusion |
| Auditable | Independent round-zero answers, structured critiques with short peer labels (less brand bias), then a brief where every claim must cite real turn IDs |
Guests can try Regular. Signed-in users unlock Auditable, persistence, tools, compaction, and sharing.
Browser (React)
→ Fastify API
→ Auth + guest quota
→ MemoryStore (guest) or PostgreSQL / Prisma (signed-in)
→ DiscussionOrchestrator
→ Mesh gateway
→ Compare API (round-zero fan-out)
→ Chat Completions (later rounds, organizer, tools)
→ optional Tavily internet_search
→ SSE stream back to the thread
Stack: React 19 + Vite frontend, Fastify 5 backend, Zod contracts in shared/, Mesh Node SDK for inference, Tavily for search, PostgreSQL for signed-in chats.
Inference path:
- Round zero fans out through Mesh Compare (
skip_comparison: true) so models answer in parallel without seeing each other. - Later rounds and the organizer use Mesh Chat Completions.
- Regular stays plain markdown.
- Auditable uses structured JSON turns and a provenance-checked organizer brief.
- Mesh keys never reach the browser.
Production deploys the built SPA and Fastify API as separate services.
Dev runs Vite on :5173 and Fastify on :3000; the browser calls the API URL from VITE_API_BASE_URL.
Models see prior turns under their real names and reply in natural prose. The organizer writes a short wrap-up in plain language. Best for exploring a question quickly and watching disagreement play out.
Built for inspection, not vibes.
- Round zero: every model answers alone.
- Later rounds: structured critiques; peers appear under short labels so brand prestige matters less.
- Organizer may not invent new reasoning.
- Each brief item must cite real turn IDs.
- Backend rejects unsupported organizer claims and surfaces invalid items separately.
- Citation buttons jump to the exact source turn in the transcript.
Auditable requires login. Guests see a lock on the tab and stay on Regular.
- Curated catalog across OpenAI, Anthropic, Google, xAI, Amazon, Mistral, DeepSeek, and NVIDIA.
- Pick 2–5 participants and 1–5 rounds from the composer.
- Live Mesh-hit estimate so you know how many calls a run will cost.
- Partial model failures do not kill the whole room.
- Models can refrain; if everyone refrains, the debate ends early.
- Stop keeps the user message, finished turns, and any visible partial Regular stream.
- Optional Internet access toggle in the Tools menu.
- Server-side
internet_searchvia Tavily (bounded searches per completion). - Signed-in only; guests are prompted to log in.
- Thread shows research activity while models search.
- Search results are evidence for models, not verified truth labels.
- Context window meter in the composer (limit / auto-compact / hard reject thresholds).
- Signed-in chats can compact older exchanges into rolling conversation memory.
- Manual Compact now, plus auto-compact after exchanges when usage climbs.
- Recent turns stay raw; older history becomes a summary boundary the council still sees.
- Owners create a public link from a saved chat.
- Snapshot is frozen: new private messages stay private until you update the shared copy.
- Public page is read-only (
/share/:token), no composer, noindex. - Revoke sharing anytime; revoked links show as unavailable.
- Token stored hashed; payload encrypted at rest.
- Clean council thread: user question, per-round model columns, stage markers, markdown bubbles.
- Dark and light themes.
- Composer with model picker, rounds, tools, context ring, and Stop.
- Collapsible rounds and scroll-to-bottom when you leave the live edge.
- Signed-in sidebar: history, rename, delete, share, new chat.
- Optional +context note injected into every run for that mode.
- Empty states that state the product promise: "Ask once. Watch models debate." / "Ask once. Inspect every claim."
| Capability | Guest | Signed in |
|---|---|---|
| Regular mode | Yes | Yes |
| Auditable mode | No | Yes |
| Internet tools | No | Yes |
| Saved chats | Session memory only | PostgreSQL |
| Compaction | Login gate | Yes |
| Share links | No | Yes |
| Mesh hits | Lifetime IP-based quota | Unlimited for now |
Google OAuth is optional.
Without it, the app stays guest-only and still runs Regular debates.
Signed-in sessions use an HS256 JWT stored by the SPA and sent as an Authorization: Bearer token, with a server-side session row retained for logout and revocation.
Guests get a hard lifetime allowance of logical Mesh hits (default 50), not an open free ride.
- Identity is a one-way HMAC of the client IP, not a cookie you can clear.
- Each council run costs
models + (models × rounds) + 1 organizer. - UI shows remaining free hits.
- When the quota is exhausted, further guest runs return
GUEST_MESH_QUOTA_EXCEEDEDand prompt login. - Signed-in users bypass this guest limit.
- Config and IP source details live in
setup.md.
- Confidence scores that pretend agreement equals truth.
- Mesh keys or OAuth tokens in the browser.
- Mixing Regular and Auditable inside one conversation.
Consensus is a signal to inspect, not a verdict to trust.
| Doc | Purpose |
|---|---|
README.md |
Product intent, architecture, features |
setup.md |
Install, env, auth, DB, deploy, tests |
AGENT.README.md |
Repo map and engineering invariants for agents |