dumbtv
dumbtv takes the ads, screen tracking and update nags out of your Fire TV over ADB. No root, none of your apps touched, every step can be undone. Free and open source.
Don't trust one AI. Verify with five. Multi-model research, claim verification, video authenticity, and governance — with audit trails.
SecurityTypeScript · JavaScriptGitHub @yasinwarsameOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
ConvergePanel is a production-ready MVP web application that sends one user question to multiple AI models in parallel, then synthesizes a unified answer while explicitly highlighting where models agree or disagree.Read the full README ↗Multi-LLM Expert Panel Research Tool
ConvergePanel is a production-ready MVP web application that sends one user question to multiple AI models in parallel, then synthesizes a unified answer while explicitly highlighting where models agree or disagree.
git clone <repository-url>
cd ConvergePanel
npm install
# or
yarn install
# or
pnpm install
.env.local file in the root directory:cp .env.example .env.local
Set up Firebase:
convergepanel (or update env vars)Get Firebase Service Account Credentials (REQUIRED for Admin SDK):
client_email → FIREBASE_CLIENT_EMAILprivate_key → FIREBASE_PRIVATE_KEY (keep the quotes and \n characters)\nAdd environment variables to .env.local:
# Firebase Client Config (from Firebase Console)
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=convergepanel.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=convergepanel
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=convergepanel.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=907484474744
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
# Firebase Admin SDK (Service Account) - REQUIRED
# Get these from Firebase Console > Project Settings > Service Accounts > Generate new private key
FIREBASE_PROJECT_ID=convergepanel
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@convergepanel.iam.gserviceaccount.com
# IMPORTANT: Keep the quotes and \n characters exactly as they appear in the JSON file
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...\n-----END PRIVATE KEY-----\n"
# Admin Secret (for setting first admin)
ADMIN_SECRET=your-long-random-secret-string
# Optional: API keys can be set here or via Admin UI
# Firestore keys take precedence over environment variables
OPENAI_API_KEY=your_openai_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here
XAI_API_KEY=your_xai_api_key_here
PERPLEXITY_API_KEY=your_perplexity_api_key_here
firestore.rules (see below)Note:
npm run dev
# or
yarn dev
# or
pnpm dev
Open http://localhost:3000 in your browser
Enter a question, select models (minimum 2), and click "Run Panel"
ConvergePanel/
├── app/
│ ├── admin/
│ │ ├── login/
│ │ │ └── page.tsx # Admin login page
│ │ └── page.tsx # Admin dashboard
│ ├── about/
│ │ └── page.tsx # About page
│ ├── help/
│ │ └── page.tsx # Help page
│ ├── contact/
│ │ └── page.tsx # Contact page
│ ├── api/
│ │ ├── admin/
│ │ │ ├── login/
│ │ │ │ └── route.ts # Admin login API
│ │ │ ├── logout/
│ │ │ │ └── route.ts # Admin logout API
│ │ │ └── keys/
│ │ │ └── route.ts # Admin keys API
│ │ └── run-panel/
│ │ └── route.ts # API endpoint for running panels
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout
│ └── page.tsx # Main page component
├── components/
│ ├── ModelPicker.tsx # Model selection UI
│ ├── StatusPill.tsx # Status indicator component
│ ├── ResultsDisplay.tsx # Results display component
│ └── TopNav.tsx # Top navigation component
├── lib/
│ ├── keyStore.ts # Server-side key storage
│ ├── types.ts # TypeScript type definitions
│ ├── consensus.ts # Consensus engine and synthesis
│ └── connectors/
│ ├── base.ts # Base connector class
│ ├── chatgpt.ts # OpenAI GPT 5.2 connector
│ ├── claude.ts # Anthropic Claude Opus 4.5 connector
│ ├── grok.ts # X.AI Grok 4 connector
│ ├── perplexity.ts # Perplexity Pro connector
│ ├── gemini.ts # Google Gemini 3 Pro connector
│ └── index.ts # Connector exports
├── middleware.ts # Route protection middleware
├── package.json
├── tsconfig.json
├── tailwind.config.ts
└── README.md
Each AI model has a dedicated connector that implements the ModelConnector interface:
interface ModelConnector {
id: "chatgpt" | "claude" | "grok" | "perplexity" | "gemini";
displayName: string;
sendPrompt(question: string, systemWrapper: string): Promise<{
status: "ok" | "error" | "timeout" | "refused";
rawText: string | null;
latencyMs: number;
}>;
}
The /api/run-panel endpoint:
The consensus engine:
To add a new model connector:
lib/connectors/ (e.g., gemini.ts):import { BaseConnector } from "./base";
export class GeminiConnector extends BaseConnector {
id = "gemini" as const;
displayName = "Gemini 3 Pro";
async sendPrompt(question: string, systemWrapper: string) {
const startTime = Date.now();
const apiKey = this.getApiKey();
if (!apiKey) {
return this.getMockResponse();
}
try {
// Implement your API call here
// ...
return {
status: "ok" as const,
rawText: responseText,
latencyMs: Date.now() - startTime,
};
} catch (error) {
// Handle errors
return {
status: "error" as const,
rawText: null,
latencyMs: Date.now() - startTime,
};
}
}
}
lib/types.ts to include the new model ID:export type ModelId = "chatgpt" | "claude" | "grok" | "perplexity" | "gemini";
lib/connectors/index.ts:import { GeminiConnector } from "./gemini";
const connectors: Record<ModelId, ModelConnector> = {
// ... existing connectors
gemini: new GeminiConnector(),
};
.env.local:GEMINI_API_KEY=your_gemini_api_key_here
getApiKey() method to include the new key mapping.ConvergePanel uses Firebase Authentication with role-based access control.
ADMIN_EMAILS address or the admin: true custom claim; a broad read/monitoring tier over runs and user records. SYSTEM_ADMIN — the admin: true claim only; API keys, role minting, purge, destructive user/billing mutation. GOVERNANCE_ADMIN — a verified, enabled GOVERNANCE_ADMIN_EMAILS address only. See docs/operations/admin-authority-tiers.md.Sign up a user account through the app (/signup)
Get the user's UID from Firebase Console or from the user's profile page
Call the admin setter endpoint. MINTS-AUTHORITY — this grants SYSTEM_ADMIN to the named uid:
curl -X POST http://localhost:3000/api/admin/set-admin \
-H "Content-Type: application/json" \
-d '{"uid": "USER_UID_HERE", "secret": "YOUR_ADMIN_SECRET"}'
Never reuse this request to check whether an old secret still works. The secret is validated before the uid, so a still-live old secret does not report a failure here — it mints the claim again, with no audit record and no log. To verify a rotation or removal, use the uid-less probe in
docs/operations/admin-authority-tiers.md§B.6 — send{"secret": "..."}with no uid.A standalone
401is NOT Production containment proof. On its own it says only that the origin you contacted rejected the string you supplied, which is also what a preview deploy with no secret set, or a shell-mangled secret, returns. A single response is an OBSERVATION:400+ the accepted marker = credential accepted,401+ the rejected marker = credential rejected, anything else = inconclusive. Containment requires the two-phase proof at the canonical Production origin — pre-check accepted, then rotate and deploy, then the SAME process observing that credential rejected.
Note: This endpoint is not linked in the UI for security. It's a one-time setup endpoint.
ConvergePanel includes an admin-only dashboard for managing API keys and users.
/admin (link appears in TopNav for admins only)admin: true custom claim for SYSTEM_ADMIN routes, and the claim or a verified, enabled ADMIN_EMAILS address for the ADMIN_PORTAL read tierappConfig/modelKeys documentImportant Security Notes:
/admin route is not linked in public navigationadmin custom claim or a verified ADMIN_EMAILS member; see docs/operations/admin-authority-tiers.md). There is no password-based admin login.ConvergePanel uses PostgreSQL with Prisma ORM for data persistence.
npm install
.env.local:DATABASE_URL="postgresql://user:password@localhost:5432/convergepanel?schema=public"
npx prisma migrate dev --name init
npx prisma generate
The database includes:
To create a new migration:
npx prisma migrate dev --name your_migration_name
To apply migrations in production:
npx prisma migrate deploy
View and edit data in a GUI:
npx prisma studio
Copy and paste these rules into Firebase Console > Firestore Database > Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users collection - users can read/write only their own doc
// Admins can list all users
match /users/{uid} {
allow read, write: if request.auth != null && request.auth.uid == uid;
allow list: if request.auth != null && request.auth.token.admin == true;
}
// App config - only admins can read/write model keys
match /appConfig/modelKeys {
allow read, write: if request.auth != null && request.auth.token.admin == true;
}
// Default deny all other documents
match /{document=**} {
allow read, write: if false;
}
}
}
| Variable | Description | Required |
|---|---|---|
NEXT_PUBLIC_FIREBASE_API_KEY | Firebase API key | Yes |
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN | Firebase auth domain | Yes |
NEXT_PUBLIC_FIREBASE_PROJECT_ID | Firebase project ID | Yes |
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET | Firebase storage bucket | Yes |
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID | Firebase messaging sender ID | Yes |
NEXT_PUBLIC_FIREBASE_APP_ID | Firebase app ID | Yes |
| Variable | Description | Required |
|---|---|---|
FIREBASE_PROJECT_ID | Firebase project ID | Yes |
FIREBASE_CLIENT_EMAIL | Service account email | Yes |
FIREBASE_PRIVATE_KEY | Service account private key | Yes |
ADMIN_SECRET | Secret for setting first admin | Yes |
| Variable | Description | Required |
|---|---|---|
OPENAI_API_KEY | OpenAI API key for GPT 5.2 | No (uses mock if missing) |
ANTHROPIC_API_KEY | Anthropic API key for Claude Opus 4.5 | No (uses mock if missing) |
XAI_API_KEY | X.AI API key for Grok 4 | No (uses mock if missing) |
PERPLEXITY_API_KEY | Perplexity API key for Perplexity Pro | No (uses mock if missing) |
GEMINI_API_KEY | Google API key for Gemini 3 Pro | No (uses mock if missing) |
Note:
npm run build
npm start
npm run lint
If you encounter a ChunkLoadError in development (e.g., "Loading chunk app/layout failed"):
Clear Next.js cache:
rm -rf .next
Clear browser cache and service workers:
Restart the dev server:
npm run dev
Hard refresh the browser:
Note: Service workers are automatically unregistered in development mode to prevent caching issues. If you still see errors, ensure no service workers are registered in your browser.
MIT
For issues or questions, please open an issue on the repository.