AETHER
Browser Extension

Aether in your browser

The Aether extension injects a "Verify with Aether" button next to every AI response on ChatGPT, Claude, Gemini, and Copilot. Click it — the tribunal runs, a trust score appears inline, and hallucinations are flagged in real time.

One-click verify
A button appears next to every AI message. Click → trust score.
Inline verdict
Trust score, verdict, and corrections — rendered below the response.
Works everywhere
ChatGPT, Claude, Gemini, Copilot — and any chat UI.
Chrome Web Store listing — coming soon.
For now: load unpacked below →
Install in 6 steps
  1. 1Download aether-extension.zip (button below) and unzip it into a folder — or create the files manually from the blocks further down.
  2. 2If you unzipped: skip to step 3. If manual: create manifest.json, background.js, content.js, popup.html, popup.js in a folder named aether-extension.
  3. 3Open chrome://extensions, enable Developer mode (top-right).
  4. 4Click "Load unpacked" and select the aether-extension folder.
  5. 5Click the Aether toolbar icon and paste your Aether API key (get one from the Portal).
  6. 6Open ChatGPT, Claude, Gemini, or Copilot — a "Verify with Aether" button appears next to each AI response. Click it.
Extension files

Download the ready-to-load .zip, unzip, and "Load unpacked" in chrome://extensions — or paste the files manually below. Endpoint origin auto-filled to https://aether.sf2x.com.

{
  "manifest_version": 3,
  "name": "Aether — The Truth Layer for AI",
  "version": "0.2.0",
  "description": "Verify any AI response. Click 'Verify with Aether' next to any chat message and get a trust score.",
  "permissions": [
    "storage",
    "activeTab"
  ],
  "host_permissions": [
    "https://chat.openai.com/*",
    "https://chatgpt.com/*",
    "https://claude.ai/*",
    "https://gemini.google.com/*",
    "https://copilot.microsoft.com/*",
    "https://aether.sf2x.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": [
        "https://chat.openai.com/*",
        "https://chatgpt.com/*",
        "https://claude.ai/*",
        "https://gemini.google.com/*",
        "https://copilot.microsoft.com/*"
      ],
      "js": [
        "content.js"
      ],
      "run_at": "document_idle"
    }
  ],
  "icons": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  },
  "action": {
    "default_popup": "popup.html",
    "default_title": "Aether — set API key",
    "default_icon": {
      "16": "icon.png",
      "48": "icon.png",
      "128": "icon.png"
    }
  }
}
// background.js — service worker
const ORIGIN = "https://aether.sf2x.com";
const ENDPOINT = ORIGIN + '/functions/verifyResponse';

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type !== 'aether-verify') return;
  (async () => {
    const { apiKey } = await chrome.storage.sync.get('apiKey');
    if (!apiKey) { sendResponse({ error: 'Set your Aether API key in the extension popup.' }); return; }
    try {
      const res = await fetch(ENDPOINT, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
        body: JSON.stringify({ text: msg.text, source: 'extension' }),
      });
      const data = await res.json();
      if (!res.ok) { sendResponse({ error: data.error || 'verification failed' }); return; }
      // store verification history (shown in the popup)
      const { history = [] } = await chrome.storage.local.get('history');
      history.unshift({ trust: data.trust_score, verdict: data.verdict, snippet: (msg.text || '').slice(0, 120), url: ORIGIN + (data.tribunal_url || ''), at: Date.now() });
      await chrome.storage.local.set({ history: history.slice(0, 50) });
      sendResponse({ data, origin: ORIGIN });
    } catch (e) { sendResponse({ error: String((e && e.message) || e) }); }
  })();
  return true; // keep the message channel open for the async response
});
// content.js — injected on ChatGPT, Claude, Gemini, Copilot
const PROCESSED = 'data-aether-processed';
const SELECTORS = [
  '[data-message-author-role="assistant"]',
  '[data-testid*="conversation-turn"]:not([data-testid*="user"])',
  '[data-testid*="assistant"]',
  '[data-message]',
  '.markdown.prose', '.prose', '.message-content',
  '[class*="agent-message"]', 'article',
];

function extractText(el) {
  const c = el.cloneNode(true);
  c.querySelectorAll('button, .aether-verify-btn, .aether-card, svg').forEach(n => n.remove());
  return (c.innerText || c.textContent || '').trim();
}
function toneColor(t) { return t >= 75 ? '#34d399' : t >= 50 ? '#fbbf24' : '#fb7185'; }
function verdictLabel(v) { return v === 'verified' ? 'Verified' : v === 'contested' ? 'Contested' : 'Rejected'; }
function escapeHtml(s) { return String(s).replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m])); }

function findMessages() {
  const out = [];
  SELECTORS.forEach(sel => {
    try { document.querySelectorAll(sel).forEach(el => {
      if (el.hasAttribute(PROCESSED)) return;
      if (el.closest('.aether-card') || el.closest('.aether-verify-btn')) return;
      if (el.parentElement && el.parentElement.closest('[' + PROCESSED + ']')) { el.setAttribute(PROCESSED, ''); return; }
      if (extractText(el).length > 60) { el.setAttribute(PROCESSED, ''); out.push(el); }
    }); } catch (e) {}
  });
  return out;
}

function injectButton(el) {
  const btn = document.createElement('button');
  btn.className = 'aether-verify-btn';
  btn.type = 'button';
  btn.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg> Verify with Aether';
  Object.assign(btn.style, {
    display: 'inline-flex', alignItems: 'center', gap: '5px', margin: '8px 0 0 0',
    padding: '4px 10px', fontSize: '12px', fontFamily: 'system-ui, sans-serif', fontWeight: '500',
    color: '#070A0F', background: 'linear-gradient(135deg,#34d399,#0d9488)', border: '0', borderRadius: '7px', cursor: 'pointer',
  });
  btn.addEventListener('click', () => {
    const text = extractText(el);
    if (!text) return;
    btn.disabled = true;
    btn.innerHTML = '<span style="display:inline-block;width:12px;height:12px;border:2px solid rgba(7,10,15,.4);border-top-color:#070A0F;border-radius:50%;animation:aether-spin .7s linear infinite"></span> Tribunal running...';
    chrome.runtime.sendMessage({ type: 'aether-verify', text }, (res) => {
      btn.disabled = false;
      btn.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg> Verify with Aether';
      if (!res) return;
      if (res.error) showError(el, res.error);
      else renderCard(el, res.data, res.origin);
    });
  });
  el.appendChild(btn);
}

function renderCard(anchor, data, origin) {
  const existing = anchor.parentElement.querySelector(':scope > .aether-card');
  if (existing) existing.remove();
  const t = data.trust_score || 0, tone = toneColor(t);
  const card = document.createElement('div');
  card.className = 'aether-card';
  card.innerHTML =
    '<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">' +
      '<div style="width:20px;height:20px;border-radius:6px;background:linear-gradient(135deg,#34d399,#0d9488);display:flex;align-items:center;justify-content:center;color:#070A0F;font-weight:700;font-size:10px">A</div>' +
      '<span style="font-weight:600;font-size:12px;color:#fff">Aether verdict</span>' +
      '<span style="font-size:10px;color:' + tone + ';margin-left:auto;font-weight:600">● ' + verdictLabel(data.verdict) + '</span>' +
    '</div>' +
    '<div style="display:flex;align-items:center;gap:10px">' +
      '<div style="font-size:26px;font-weight:700;color:' + tone + '">' + t + '<span style="font-size:12px;color:#64748b">/100</span></div>' +
      '<div style="flex:1;height:5px;border-radius:99px;background:#1f2937;overflow:hidden"><div style="height:100%;width:' + Math.max(2,t) + '%;background:' + tone + ';border-radius:99px"></div></div>' +
    '</div>' +
    (data.corrections && data.corrections.length ?
      '<div style="margin-top:9px;border-top:1px solid #1f2937;padding-top:8px"><div style="font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:#fb7185;margin-bottom:4px">Issues (' + data.corrections.length + ')</div>' +
      data.corrections.slice(0,3).map(c => '<div style="font-size:11px;color:#94a3b8;margin-bottom:3px">• ' + escapeHtml(c) + '</div>').join('') + '</div>' : '') +
    '<a href="' + escapeHtml(origin + (data.tribunal_url || ('/verify/' + (data.lineage_id||'')))) + '" target="_blank" rel="noreferrer" style="display:inline-block;margin-top:8px;font-size:11px;color:#34d399;text-decoration:none">View full tribunal debate →</a>';
  Object.assign(card.style, { fontFamily: 'system-ui, sans-serif', marginTop: '8px', padding: '12px 14px', background: '#0B0F16', color: '#e2e8f0', border: '1px solid #1f2937', borderRadius: '12px', maxWidth: '420px', boxShadow: '0 8px 30px rgba(0,0,0,.4)' });
  anchor.parentElement.insertBefore(card, anchor.nextSibling);
}

function showError(el, msg) {
  const existing = el.parentElement.querySelector(':scope > .aether-card');
  if (existing) existing.remove();
  const n = document.createElement('div');
  n.className = 'aether-card';
  n.textContent = 'Aether: ' + msg;
  Object.assign(n.style, { marginTop: '8px', padding: '10px 12px', background: '#0B0F16', color: '#fb7185', border: '1px solid #1f2937', borderRadius: '10px', fontSize: '12px', fontFamily: 'system-ui, sans-serif', maxWidth: '420px' });
  el.parentElement.insertBefore(n, el.nextSibling);
  setTimeout(() => n.remove(), 5000);
}

function scan() { findMessages().forEach(injectButton); }
const style = document.createElement('style');
style.textContent = '@keyframes aether-spin { to { transform: rotate(360deg); } }';
document.head.appendChild(style);
scan();
new MutationObserver(() => scan()).observe(document.body, { childList: true, subtree: true });
setInterval(scan, 3000);
<!doctype html>
<html><head><meta charset="utf-8"><style>
  body { width: 300px; font: 13px system-ui; background:#070A0F; color:#e2e8f0; padding: 14px; margin:0 }
  h3 { margin: 0 0 4px; font-size: 15px; display:flex; align-items:center; gap:6px }
  .sub { font-size: 10px; letter-spacing:.14em; text-transform:uppercase; color:#64748b; margin-bottom:12px }
  p { font-size: 11px; color:#94a3b8; margin: 0 0 10px }
  input { width:100%; box-sizing:border-box; padding:7px 9px; background:#0B0F16; border:1px solid #1f2937; border-radius:8px; color:#fff; font-size:12px }
  button { margin-top:9px; width:100%; padding:7px; background:#10b981; border:0; border-radius:8px; color:#070A0F; font-weight:600; cursor:pointer }
  #m { font-size: 11px; color:#34d399; margin-top: 6px }
  .hist { margin-top:14px; border-top:1px solid #1f2937; padding-top:10px; max-height:180px; overflow:auto }
  .hist h4 { font-size:10px; letter-spacing:.12em; text-transform:uppercase; color:#64748b; margin:0 0 6px }
  .row { padding:7px 0; border-bottom:1px solid #1f2937; font-size:11px }
  .row a { color:#34d399; text-decoration:none }
  .dot { display:inline-block; width:7px; height:7px; border-radius:50%; margin-right:5px }
</style></head><body>
  <h3>🛡️ Aether</h3>
  <div class="sub">The Truth Layer for AI</div>
  <p>Paste your Aether API key (sk_…). Stored locally in this browser only.</p>
  <input id="k" placeholder="sk_sf2x_…" />
  <button id="s">Save key</button>
  <div id="m"></div>
  <div class="hist" id="h"><h4>Recent verifications</h4></div>
  <script src="popup.js"></script>
</body></html>
// popup.js
function tone(t){ return t>=75?'#34d399':t>=50?'#fbbf24':'#fb7185'; }
function verdict(v){ return v==='verified'?'Verified':v==='contested'?'Contested':'Rejected'; }

document.getElementById('s').onclick = async () => {
  const k = document.getElementById('k').value.trim();
  await chrome.storage.sync.set({ apiKey: k });
  document.getElementById('m').textContent = 'Saved.';
};

(async () => {
  const { apiKey } = await chrome.storage.sync.get('apiKey');
  if (apiKey) document.getElementById('k').value = apiKey;
  const { history = [] } = await chrome.storage.local.get('history');
  const h = document.getElementById('h');
  if (!history.length) { h.innerHTML += '<div style="font-size:11px;color:#475569">No verifications yet.</div>'; return; }
  history.slice(0, 12).forEach(r => {
    const c = tone(r.trust);
    const div = document.createElement('div');
    div.className = 'row';
    div.innerHTML = '<span class="dot" style="background:' + c + '"></span><b style="color:' + c + '">' + r.trust + '</b> ' + verdict(r.verdict) + ' <a href="' + r.url + '" target="_blank">view →</a><div style="color:#64748b;font-size:10px;margin-top:2px">' + (r.snippet||'').slice(0,70) + '</div>';
    h.appendChild(div);
  });
})();
Chrome Web Store listing

Paste these into the Developer Dashboard. Privacy policy points at your app's /privacy page.

https://aether.sf2x.com/privacy
Verify the factual trustworthiness of AI-generated text by sending the response the user selects to the Aether verification service.
storage — Stores only the user's Aether API key and a local log of recent verifications (trust score, snippet, link). No browsing history is collected.
activeTab + host_permissions (chat.openai.com, chatgpt.com, claude.ai, gemini.google.com, copilot.microsoft.com) — Reads the visible AI response the user clicks "Verify" on so it can be sent to Aether for verification. No other page content, form inputs, credentials, or personal data is read or transmitted.
Verify any AI response — click 'Verify with Aether' next to a chat message for an instant trust score and hallucination flags.
Aether — The Truth Layer for AI.

The Aether browser extension adds a "Verify with Aether" button next to every AI response on ChatGPT, Claude, Gemini, and Copilot. Click it and Aether's independent tribunal runs a multi-model verification: the response is checked against authoritative sources, decomposed into atomic claims, and scored for trust. A trust score (0–100), verdict, and any factual corrections appear inline beneath the answer — so you can see at a glance whether an AI response is verified, contested, or rejected.

Your API key is stored only in your browser's sync storage; no page content other than the message you choose to verify is sent anywhere.

Don't trust. Verify.
Submission checklist
  • Upload aether-extension.zip via "Add new item" → "Upload a package".
  • Set Category: Productivity.
  • Upload the 128×128 store icon (download below) to the Icon field.
  • Add 1–5 screenshots (1280×800) — capture ChatGPT with the Verify button + verdict card.
  • Paste the Privacy policy URL, Single purpose, and Permission justification above.
  • Submit for review — Chrome will ask you to justify the chat-site host permissions (normal).

Generate one in the Portal, then paste it into the extension popup. It lives only in your browser's sync storage.