⚡ ActionLedger

Runtime action trust for AI agents.

Score, explain, and record whether an AI agent should trust a tool, response, peer, memory, or destination before acting.

Every agent action gets a verdict, confidence level, recommended action, and audit-ready proof record.

View Developer Quickstart

Try an action trust scan

Enter a URL to see how ActionLedger scores an agent action before execution. Verdict confidence tells you how sure the system is — not how safe the URL is.

Try an example:

Use examples to see how ActionLedger handles safe destinations, impersonation, redirects, malicious responses, and exploit-pattern payloads.

Running in demo mode — no API key needed. Get full API access →

🚫 Blocked: This connection is high risk. Do not allow your agent to proceed.
⚠ Uncertain result. Review before allowing — additional signals may be needed.
Latency: ms

    🎉 Ready to use this in your agent? Start with the API quickstart — no credit card needed.

    View Quickstart →

    Why agent actions need proof

    AI agents are no longer just generating text. They call tools, fetch URLs, process files, update memory, delegate work, and interact with other agents. Every one of those actions can introduce risk.

    ActionLedger evaluates those actions before they happen, explains the decision, and records the evidence so teams know what was allowed, blocked, or escalated — and why.

    How it works

    Score. Explain. Record. Govern.

    🔍

    1. Score the action

    Evaluate the requested tool, URL, response, peer, memory, or destination.

    💡

    2. Explain the risk

    Return a risk score, verdict confidence, risk factors, and recommended action.

    🛂

    3. Govern the decision

    Apply policy to allow, block, or require human review.

    🧾

    4. Record the proof

    Create an audit-ready record showing what was checked, why it mattered, and what decision was made.

    Product Pillars

    Four capabilities that make agent actions trustworthy, auditable, and governable.

    Runtime Trust Decisions

    Fast action scoring before agent actions execute. Every interaction gets a verdict, confidence level, and recommended action in under 50ms.

    🧾

    Proof Records

    Evidence and receipts showing why an action was allowed, blocked, or reviewed. Signed and tamper-evident for audit and compliance.

    🧠

    Shared Agent Memory

    Canonical goals, decisions, definitions, tasks, failed attempts, and handoffs readable by every agent in the workflow.

    🤝

    Delegation Controls

    Peer-agent trust checks, semantic drift detection, and provenance for delegated work. Human review for uncertain or high-risk handoffs.

    Developer Access

    Use ActionLedger through the live scanner, API, or SDK.

    ▶ Try Live Demo 📚 Quickstart ⬡ GitHub SDK
    UNION SELECT password FROM users; ../../etc/passwd" } }; function tryDemo(key) { const ex = DEMO_EXAMPLES[key]; if (!ex) return; document.getElementById('url-input').value = ex.url; const rtEl = document.getElementById('response-input'); if (rtEl) rtEl.value = ex.response_text || ''; doScan(); } function tryExample(url) { document.getElementById('url-input').value = url; const rtEl = document.getElementById('response-input'); if (rtEl) rtEl.value = ''; doScan(); } async function doScan() { const urlInput = document.getElementById('url-input'); const btn = document.getElementById('scan-btn'); const errEl = document.getElementById('scan-error'); const resultBox = document.getElementById('result-box'); const gaugeArea = document.getElementById('gauge-area'); const postCta = document.getElementById('post-demo-cta'); const viralEl = document.getElementById('viral-prompt'); const url = urlInput.value.trim(); if (!url) { urlInput.focus(); return; } // Reset state errEl.style.display = 'none'; resultBox.style.display = 'none'; gaugeArea.style.display = 'none'; postCta.style.display = 'none'; if (viralEl) viralEl.style.display = 'none'; document.getElementById('alert-malicious').style.display = 'none'; document.getElementById('alert-uncertain').style.display = 'none'; btn.disabled = true; btn.innerHTML = 'Scanning…'; try { const responseText = (document.getElementById('response-input')?.value || '').trim(); const scanBody = { url }; if (responseText) scanBody.response_text = responseText; const res = await fetch('/api/scan_tool', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-session-id': _sessionId, }, body: JSON.stringify(scanBody), }); const d = await res.json(); if (!res.ok) { const msg = d.detail?.message || d.message || d.detail || 'Scan failed. Try again.'; errEl.textContent = typeof msg === 'string' ? msg : JSON.stringify(msg); errEl.style.display = 'block'; return; } _demoScanCount++; // Verdict badge const verdict = d.verdict || d.result || 'UNKNOWN'; const verdictEl = document.getElementById('res-verdict'); verdictEl.textContent = verdict; verdictEl.className = 'verdict-badge verdict-' + verdict; // Meta row document.getElementById('res-latency').textContent = d.latency_ms ?? '—'; document.getElementById('res-demo-tag').innerHTML = d.demo_mode ? 'DEMO' : ''; // Gauges setGauge(d.risk_score ?? 0); setConfBar(d.confidence || 'MEDIUM'); setConfHint(d.confidence || 'MEDIUM', verdict); gaugeArea.style.display = 'block'; // Action const action = d.recommended_action || d.user_experience?.recommended_action || ''; const actionEl = document.getElementById('res-action'); actionEl.textContent = action.toUpperCase() || '—'; actionEl.className = 'value action-' + action.toLowerCase(); // Summary document.getElementById('res-summary').textContent = d.summary || '—'; // Risk factors const factors = d.risk_factors || []; const factorsEl = document.getElementById('res-factors'); factorsEl.innerHTML = factors.length === 0 ? '
  • No significant risk factors detected.
  • ' : factors.map(f => `
  • ${f}
  • `).join(''); // Why? body const reason = d.decision_reason || d.confidence_reason || d.summary || ''; document.getElementById('why-text').textContent = reason || 'No additional detail available for this result.'; document.getElementById('why-body').classList.remove('open'); document.getElementById('why-arrow').textContent = '▶'; // Context alerts if (verdict === 'MALICIOUS') { document.getElementById('alert-malicious').style.display = 'block'; } else if (d.confidence === 'LOW') { document.getElementById('alert-uncertain').style.display = 'block'; } // Usage warning from backend if (d.usage_warning && d.usage_warning.level) { const uw = document.getElementById('usage-warning-banner'); if (uw) { uw.textContent = d.usage_warning.message; uw.style.background = d.usage_warning.level === 'critical' ? 'rgba(239,68,68,.15)' : 'rgba(251,191,36,.1)'; uw.style.borderColor = d.usage_warning.level === 'critical' ? '#ef4444' : '#fbbf24'; uw.style.display = 'block'; } } // Shareable link const shareLink = location.origin + location.pathname + '?url=' + encodeURIComponent(url); const shareLinkEl = document.getElementById('share-link'); if (shareLinkEl) shareLinkEl.value = shareLink; const shareBoxEl = document.getElementById('share-box'); if (shareBoxEl) shareBoxEl.style.display = 'flex'; resultBox.style.display = 'block'; // Post-demo CTA after first scan if (_demoScanCount >= 1) { postCta.style.display = 'flex'; } // Viral loop prompt after 2+ scans if (_demoScanCount >= 2 && viralEl) { viralEl.style.display = 'block'; } } catch (e) { errEl.innerHTML = ` Demo temporarily unavailable
    The live scan service is having trouble right now. Retry   or   Get API key instead → `; errEl.style.display = 'block'; } finally { btn.disabled = false; btn.textContent = 'Scan URL'; } } function copyShareLink() { const el = document.getElementById('share-link'); if (el) { navigator.clipboard?.writeText(el.value); const btn = document.getElementById('share-link-btn'); if (btn) { btn.textContent = 'Copied!'; setTimeout(() => btn.textContent = 'Copy Link', 2000); } } } function shareOnTwitter() { const el = document.getElementById('share-link'); const url = el ? el.value : location.href; const text = encodeURIComponent('Just scanned a URL with ActionLedger — instant AI security scoring in <300ms. Try it: '); window.open(`https://twitter.com/intent/tweet?text=${text}&url=${encodeURIComponent(url)}`, '_blank'); } document.getElementById('url-input').addEventListener('keydown', e => { if (e.key === 'Enter') doScan(); }); // ── Auto-run scan if ?url= param is present ─────────────────────────────── (() => { const prescan = new URLSearchParams(location.search).get('url'); if (prescan) { const inp = document.getElementById('url-input'); if (inp) { inp.value = prescan; doScan(); } } })(); // ── API key generation ─────────────────────────────────────────────────────── async function getKey() { const name = document.getElementById('key-name').value.trim(); const email = document.getElementById('key-email').value.trim(); const tier = document.getElementById('key-tier').value; const interestEl = document.getElementById('key-interest'); const interest = interestEl ? interestEl.value : 'builder'; const btn = document.getElementById('key-btn'); const errEl = document.getElementById('key-error'); const resEl = document.getElementById('key-result'); if (!name) { document.getElementById('key-name').focus(); errEl.textContent = 'Please enter a name for your agent or project.'; errEl.style.display = 'block'; return; } errEl.style.display = 'none'; resEl.style.display = 'none'; btn.disabled = true; btn.innerHTML = 'Creating…'; try { const body = { name, tier, interest_type: interest }; if (email) body.email = email; if (_urlRef) body.referral_code = _urlRef; const res = await fetch('/api/create_key', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); const d = await res.json(); if (!res.ok) { errEl.textContent = d.detail?.message || d.message || 'Failed to create key. Try again.'; errEl.style.display = 'block'; return; } document.getElementById('key-value').textContent = d.api_key; document.getElementById('key-tier-display').textContent = d.tier; document.getElementById('key-rate').textContent = d.rate_limit_per_min; document.getElementById('key-quota').textContent = (d.monthly_quota || 0).toLocaleString(); // Show referral code const refEl = document.getElementById('key-referral-code'); if (refEl && d.referral_code) { refEl.textContent = d.referral_code; const refBox = document.getElementById('key-referral-box'); if (refBox) refBox.style.display = 'block'; const refShareLink = location.origin + '/?ref=' + d.referral_code; const refLinkEl = document.getElementById('key-referral-link'); if (refLinkEl) refLinkEl.textContent = refShareLink; } const curlText = `curl -s -X POST /api/scan_tool \\\n -H 'Content-Type: application/json' \\\n -H 'x-api-key: ${d.api_key}' \\\n -d '{"url": "https://example.com"}'`; const curlEl = document.getElementById('key-curl'); // Remove old text nodes, keep the button [...curlEl.childNodes].filter(n => n.nodeType === 3).forEach(n => n.remove()); curlEl.appendChild(document.createTextNode(curlText)); resEl.style.display = 'block'; resEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } catch { errEl.textContent = 'Network error — try again.'; errEl.style.display = 'block'; } finally { btn.disabled = false; btn.textContent = 'Generate Key →'; } } function copyKey() { navigator.clipboard?.writeText(document.getElementById('key-value').textContent); } function copyCurl() { const curlEl = document.getElementById('key-curl'); const text = [...curlEl.childNodes] .filter(n => n.nodeType === 3).map(n => n.textContent).join(''); navigator.clipboard?.writeText(text); } function copyCurlExample() { navigator.clipboard?.writeText(document.getElementById('curl-example').textContent); } function copyRefLink() { const el = document.getElementById('key-referral-link'); if (el) navigator.clipboard?.writeText(el.textContent); }