<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Portail — Unified Proxy/Gateway</title>
<meta http-equiv="Strict-Transport-Security" content="max-age=31536000; includeSubDomains; preload">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-Frame-Options" content="DENY">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
<meta http-equiv="Permissions-Policy" content="camera=(), microphone=(), geolocation=()">
<meta property="og:title" content="Portail — Unified Proxy/Gateway">
<meta property="og:description" content="AI Gateway + MCP Gateway + CDN cache + Agent-to-Agent protocol">
<meta property="og:url" content="https://portail.vaked.dev">
<meta property="og:type" content="website">
<link rel="canonical" href="https://portail.vaked.dev">
<style>
:root {
--bg: #0a0a0a;
--fg: #e0e0e0;
--accent: #00d4ff;
--accent2: #7c3aed;
--dim: #666;
--success: #44cc11;
--error: #e05d44;
--warning: #dfb317;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'SF Mono', 'Fira Code', monospace;
background: var(--bg);
color: var(--fg);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
}
header {
padding: 4rem 0 2rem 0;
text-align: center;
border-bottom: 1px solid #222;
}
h1 {
font-size: 3rem;
font-weight: 300;
letter-spacing: 0.5em;
margin-bottom: 1rem;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
nav.nav-bar {
display: flex; gap: 0.8rem; justify-content: center; flex-wrap: wrap; margin-top: 1.5rem; font-family: monospace; font-size: 0.8rem;
}
nav.nav-bar a {
padding: 0.5rem 1rem; border-radius: 8px; text-decoration: none; font-weight: bold; transition: opacity 0.2s;
}
nav.nav-bar a:hover { opacity: 0.8; }
.tagline {
color: var(--dim);
font-size: 1.1rem;
max-width: 600px;
margin: 0 auto;
}
.badges {
margin-top: 2rem;
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.badge {
background: #1a1a1a;
padding: 0.5rem 1rem;
border-radius: 4px;
font-size: 0.85rem;
color: var(--dim);
text-decoration: none;
border: 1px solid #333;
transition: all 0.2s ease;
}
.badge:hover {
border-color: var(--accent);
color: var(--accent);
}
.ci-status {
margin-top: 2rem;
padding: 1rem;
background: #111;
border-radius: 8px;
border: 1px solid #222;
display: inline-flex;
align-items: center;
gap: 0.75rem;
font-size: 0.95rem;
}
.ci-indicator {
font-size: 1.2rem;
animation: pulse 2s infinite;
}
.ci-passing { color: var(--success); }
.ci-failing { color: var(--error); }
.ci-progress { color: var(--warning); }
.ci-unknown { color: var(--dim); }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.ci-details {
font-size: 0.8rem;
color: var(--dim);
}
.ci-link {
color: var(--accent);
text-decoration: none;
font-size: 0.85rem;
}
.ci-link:hover {
text-decoration: underline;
}
section {
padding: 4rem 0;
border-bottom: 1px solid #111;
}
h2 {
font-size: 1.5rem;
font-weight: 400;
margin-bottom: 2rem;
color: var(--accent);
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.feature {
background: #111;
padding: 2rem;
border-radius: 8px;
border: 1px solid #222;
transition: border-color 0.2s ease;
}
.feature:hover {
border-color: var(--accent);
}
.feature h3 {
font-size: 1.1rem;
margin-bottom: 1rem;
color: var(--fg);
}
.feature p {
color: var(--dim);
font-size: 0.9rem;
}
code {
background: #1a1a1a;
padding: 0.2rem 0.5rem;
border-radius: 3px;
font-size: 0.85rem;
}
pre {
background: #111;
padding: 1.5rem;
border-radius: 8px;
overflow-x: auto;
border: 1px solid #222;
margin: 1rem 0;
}
pre code {
background: none;
padding: 0;
}
.ascii-art {
font-size: 0.7rem;
line-height: 1.2;
color: var(--accent);
white-space: pre;
}
footer {
padding: 2rem 0;
text-align: center;
color: var(--dim);
font-size: 0.85rem;
}
a {
color: var(--accent);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.endpoint-table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
}
.endpoint-table th,
.endpoint-table td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid #222;
}
.endpoint-table th {
color: var(--accent);
font-weight: 500;
}
.endpoint-table code {
font-size: 0.85rem;
}
.method {
display: inline-block;
padding: 0.2rem 0.5rem;
border-radius: 3px;
font-size: 0.75rem;
font-weight: bold;
min-width: 50px;
text-align: center;
}
.method-get { background: #1a472a; color: #44cc11; }
.method-post { background: #4a2a1a; color: #e05d44; }
.method-delete { background: #4a1a1a; color: #e05d44; }
.method-put { background: #4a4a1a; color: #dfb317; }
</style>
<meta name="robots" content="index, follow, max-image-preview:large">
<meta name="theme-color" content="#05060a">
<link rel="canonical" href="https://portail.vaked.dev/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="vaked.dev">
<meta property="og:title" content="Portail — Unified AI Gateway, MCP Gateway & A2A Router">
<meta property="og:description" content="High-performance zero-copy Rust gateway for AI models, MCP tools, and agent networks.">
<meta property="og:url" content="https://portail.vaked.dev/">
<meta property="og:image" content="https://art.vaked.dev/assets/og-vision-gallery.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@peterlodri">
<meta name="twitter:title" content="Portail — Unified AI & MCP Gateway in Rust">
<meta name="twitter:description" content="High-performance zero-copy Rust gateway with A2A routing and BitNet b1.58 support.">
<meta name="twitter:image" content="https://art.vaked.dev/assets/og-vision-gallery.jpg">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Portail \u2014 Unified Proxy & Gateway",
"description": "High-performance AI Gateway, MCP Gateway, A2A Router, CDN Cache & Observability in Rust.",
"url": "https://portail.vaked.dev/",
"image": "https://art.vaked.dev/assets/og-vision-gallery.jpg",
"author": {
"@type": "Person",
"name": "Peter Lodri",
"url": "https://art.vaked.dev/"
}
}
</script>
<a href="#main" class="skip-link">Skip to main content</a>
<style>
.skip-link{position:absolute;top:-100px;left:16px;z-index:100;background:#b48bff;color:#05060a;font-family:monospace;font-weight:700;padding:12px 20px;border-radius:8px;text-decoration:none;transition:top 0.2s}
.skip-link:focus{top:16px;outline:3px solid #62e6c9}
a:focus-visible,button:focus-visible{outline:2.5px solid #62e6c9!important;outline-offset:3px!important}
</style>
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="manifest" href="/site.webmanifest">
<meta name="theme-color" content="#05060a">
<link rel="alternate" type="application/rss+xml" title="Portail RSS Feed" href="/feed.xml">
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml">
</head>
<body>
<header>
<div class="container">
<img src="logo.svg" width="120" height="120" alt="Portail Logo" style="margin-bottom: 1rem;">
<h1>PORTAIL</h1>
<p class="tagline">Unified proxy/gateway: AI Gateway + MCP Gateway + CDN cache + Agent-to-Agent protocol</p>
<nav class="nav-bar">
<a href="/showcase.html" style="background:rgba(180,139,255,0.15); border:1px solid rgba(180,139,255,0.3); color:#b48bff;">🚀 Showcase</a>
<a href="/sgc_wasm_demo.html" style="background:rgba(98,230,201,0.15); border:1px solid rgba(98,230,201,0.3); color:#62e6c9;">⚡ WASM Sandbox</a>
<a href="/status.html" style="background:rgba(255,207,92,0.15); border:1px solid rgba(255,207,92,0.3); color:#ffcf5c;">📊 Telemetry Status</a>
<a href="/projects_knowledge_graph.html" style="background:rgba(255,255,255,0.1); border:1px solid rgba(255,255,255,0.2); color:#e7e2f7;">🗺️ D3 Graph</a>
<a href="/feed.xml" style="background:rgba(255,140,0,0.15); border:1px solid rgba(255,140,0,0.3); color:#ff8c00;">📰 RSS 2.0</a>
</nav>
<div class="badges">
<a href="https://github.com/peterlodri-sec/portail/actions" class="badge">CI</a>
<a href="https://crates.io/crates/portail" class="badge">crates.io</a>
<a href="https://github.com/peterlodri-sec/portail" class="badge">GitHub</a>
<a href="https://docs.rs/portail" class="badge">docs.rs</a>
</div>
<div class="social-links" style="margin-top: 1.5rem; display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap;">
<a href="https://pocoo.vaked.dev" style="color: var(--dim); text-decoration: none;">📝 Blog</a>
<a href="https://github.com/peterlodri-sec" style="color: var(--dim); text-decoration: none;">🐙 GitHub</a>
<a href="https://x.com/0xp3t3rl" style="color: var(--dim); text-decoration: none;">𝕏 Twitter</a>
<a href="https://patreon.com/vaked" style="color: var(--dim); text-decoration: none;">☕ Patreon</a>
<a href="https://chat.vaked.dev" style="color: var(--dim); text-decoration: none;">💬 Chat</a>
<a href="https://music.vaked.dev" style="color: var(--dim); text-decoration: none;">🎵 Music</a>
</div>
<div id="ci-status" class="ci-status">
<span id="ci-indicator" class="ci-indicator ci-unknown">●</span>
<div>
<span id="ci-text" class="ci-text">Loading CI status...</span>
<div id="ci-details" class="ci-details"></div>
</div>
<a href="https://github.com/peterlodri-sec/portail/actions" class="ci-link" target="_blank">View runs →</a>
</div>
</div>
</header>
<script>
const API_BASE = 'https://portail.vaked.dev';
async function updateCIStatus() {
try {
const resp = await fetch(`${API_BASE}/ci/status`, {
headers: { 'Accept': 'application/json' }
});
if (resp.ok) {
const data = await resp.json();
const indicator = document.getElementById('ci-indicator');
const text = document.getElementById('ci-text');
const details = document.getElementById('ci-details');
const statusMap = {
'passing': { class: 'ci-passing', text: 'CI: Passing', icon: '✓' },
'failing': { class: 'ci-failing', text: 'CI: Failing', icon: '✗' },
'in_progress': { class: 'ci-progress', text: 'CI: In Progress', icon: '⟳' },
'unknown': { class: 'ci-unknown', text: 'CI: Unknown', icon: '?' }
};
const status = statusMap[data.overall] || statusMap.unknown;
indicator.className = 'ci-indicator ' + status.class;
indicator.textContent = status.icon;
text.textContent = status.text;
if (data.total_runs > 0) {
details.textContent = `${data.success_rate.toFixed(0)}% success rate • ${data.total_runs} runs`;
}
document.title = `[${status.icon}] Portail — Unified Proxy/Gateway`;
}
} catch (e) {
document.getElementById('ci-indicator').textContent = '○';
document.getElementById('ci-text').textContent = 'CI: Offline';
document.getElementById('ci-details').textContent = 'Portail not running';
}
}
updateCIStatus();
setInterval(updateCIStatus, 30000);
if (window.EventSource) {
const source = new EventSource(`${API_BASE}/ci/live`);
source.addEventListener('ci', function(e) {
updateCIStatus();
});
source.onerror = function() {
setTimeout(() => {
source.close();
new EventSource(`${API_BASE}/ci/live`);
}, 5000);
};
}
</script>
<section>
<div class="container">
<h2>Features</h2>
<div class="features">
<div class="feature">
<h3>AI Gateway</h3>
<p>Stream proxy to LiteLLM/OpenAI/Anthropic with hook injection. OpenAI-compatible API on <code>/v1/chat/completions</code>.</p>
</div>
<div class="feature">
<h3>MCP Gateway</h3>
<p>Unix socket proxy to Python sidecar for tool execution. Zero-copy framed protocol.</p>
</div>
<div class="feature">
<h3>CDN Cache</h3>
<p>Two-tier cache: moka memory + blake3 filesystem. NATS invalidation. SIMD-optimized hashing.</p>
</div>
<div class="feature">
<h3>A2A Protocol</h3>
<p>Google Agent-to-Agent: agent cards, task lifecycle, message streaming. Self-hosted, self-managed.</p>
</div>
<div class="feature">
<h3>A2C Interface</h3>
<p>Agent-to-Consumer: human-facing chat API with tool use. First-class agent support.</p>
</div>
<div class="feature">
<h3>TUI Dashboard</h3>
<p>Live network visualization with sparklines. Keyboard navigation. Zero-alloc rendering.</p>
</div>
</div>
</div>
</section>
<section>
<div class="container">
<h2>API Endpoints</h2>
<table class="endpoint-table">
<thead>
<tr>
<th>Endpoint</th>
<th>Method</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/healthz</code></td>
<td><span class="method method-get">GET</span></td>
<td>Health check</td>
</tr>
<tr>
<td><code>/v1/chat/completions</code></td>
<td><span class="method method-post">POST</span></td>
<td>OpenAI-compatible chat</td>
</tr>
<tr>
<td><code>/a2c/chat</code></td>
<td><span class="method method-post">POST</span></td>
<td>Agent-to-Consumer chat</td>
</tr>
<tr>
<td><code>/.well-known/agent.json</code></td>
<td><span class="method method-get">GET</span></td>
<td>A2A agent card</td>
</tr>
<tr>
<td><code>/a2a/tasks</code></td>
<td><span class="method method-post">POST</span></td>
<td>Create A2A task</td>
</tr>
<tr>
<td><code>/events</code></td>
<td><span class="method method-get">GET</span></td>
<td>Recent events</td>
</tr>
<tr>
<td><code>/events/stream</code></td>
<td><span class="method method-get">GET</span></td>
<td>SSE event stream</td>
</tr>
<tr>
<td><code>/hooks</code></td>
<td><span class="method method-get">GET</span></td>
<td>List hooks</td>
</tr>
<tr>
<td><code>/ci/status</code></td>
<td><span class="method method-get">GET</span></td>
<td>CI status JSON</td>
</tr>
<tr>
<td><code>/ci/badge</code></td>
<td><span class="method method-get">GET</span></td>
<td>SVG badge</td>
</tr>
<tr>
<td><code>/ci/webhook</code></td>
<td><span class="method method-post">POST</span></td>
<td>GitHub webhook</td>
</tr>
<tr>
<td><code>/metrics</code></td>
<td><span class="method method-get">GET</span></td>
<td>Prometheus metrics</td>
</tr>
</tbody>
</table>
</div>
</section>
<section>
<div class="container">
<h2>Quick Start</h2>
<pre><code># Install
cargo install portail
# Run with defaults (AI gateway on :8787)
portail serve
# Launch interactive TUI dashboard
portail
# Check CI status
curl https://portail.vaked.dev/ci/status
# Get CI badge
curl https://portail.vaked.dev/ci/badge > badge.svg</code></pre>
</div>
</section>
<section>
<div class="container">
<h2>Performance Engines</h2>
<div class="features">
<div class="feature">
<h3>eBPF</h3>
<p>Kernel-level observability. Trace syscalls, measure network latency, monitor scheduler — all without modifying application code.</p>
</div>
<div class="feature">
<h3>io_uring</h3>
<p>Async I/O engine (Linux 5.1+). Single syscall for batch submissions, zero-copy reads, reduced context switches.</p>
</div>
<div class="feature">
<h3>DPDK</h3>
<p>Kernel bypass for extreme performance. Direct NIC access via Poll Mode Driver. Requires dedicated NIC + hugepages.</p>
</div>
<div class="feature">
<h3>Hyper</h3>
<p>Low-level HTTP engine. Direct control over HTTP/2 settings, connection pooling, flow control. Skip axum overhead.</p>
</div>
</div>
</div>
</section>
<section>
<div class="container">
<h2>Architecture</h2>
<pre class="ascii-art">┌─────────────────────────────────────────────────────────────┐
│ portail binary │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ proxy │ │ cdn │ │ events │ │ hooks │ │
│ │ (axum) │ │ (moka) │ │ (ring) │ │ (inject)│ │
│ └─────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ┌─────┴──────────────┴──────────────┴──────────────┴─────┐ │
│ │ AppState (shared) │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ sentinel │ │ mcp │ │ a2a │ │ a2c │ │
│ │ (health) │ │ (sidecar)│ │ (agent) │ │ (chat) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ ci │ │ nullclaw│ │ godfather│ │ discovery│ │
│ │ (webhook)│ │ (heartbeat│ │ (monitor)│ │ (network)│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘</pre>
</div>
</section>
<footer role="contentinfo" style="position:relative;z-index:10;padding:3rem 1.5rem;text-align:center;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:0.75rem;letter-spacing:0.14em;color:#a59fc4;background:rgba(5,6,10,0.92);border-top:1px solid rgba(170,150,255,0.18);backdrop-filter:blur(16px);margin-top:4rem;">
<div style="margin-bottom:0.5rem;text-transform:uppercase;letter-spacing:0.3em;color:#b48bff;font-weight:600;">the constellation · lovetta lane · portail</div>
<div style="margin-bottom:1rem;font-size:0.65rem;letter-spacing:0.22em;color:#a59fc4;text-transform:uppercase;">keep the weights warm</div>
<div style="display:flex;gap:0.8rem;justify-content:center;flex-wrap:wrap;margin-bottom:1.5rem;">
<a href="https://github.com/sponsors/peterlodri-sec" target="_blank" rel="noopener noreferrer" style="color:#62e6c9;text-decoration:none;border:1px solid rgba(98,230,201,0.35);border-radius:8px;padding:0.45rem 0.9rem;background:rgba(98,230,201,0.06);">github sponsor</a>
<a href="https://revolut.me/peterjs8be" target="_blank" rel="noopener noreferrer" style="color:#62e6c9;text-decoration:none;border:1px solid rgba(98,230,201,0.35);border-radius:8px;padding:0.45rem 0.9rem;background:rgba(98,230,201,0.06);">revolut</a>
<a href="https://wise.com/pay/business/lodripeterjozsef" target="_blank" rel="noopener noreferrer" style="color:#62e6c9;text-decoration:none;border:1px solid rgba(98,230,201,0.35);border-radius:8px;padding:0.45rem 0.9rem;background:rgba(98,230,201,0.06);">wise</a>
</div>
<nav aria-label="Constellation sister sites" style="display:flex;gap:1rem;justify-content:center;flex-wrap:wrap;font-size:0.7rem;">
<a href="https://art.vaked.dev/" style="color:#62e6c9;text-decoration:none;">art.vaked.dev</a> ·
<a href="https://art.vaked.dev/vision-gallery.html" style="color:#5b9dff;text-decoration:none;">✦ vision-gallery (23)</a> ·
<a href="https://music.vaked.dev/" target="_blank" rel="noopener noreferrer" style="color:#a59fc4;text-decoration:none;">music.vaked.dev</a> ·
<a href="https://mlxquantlovefrom.com/" target="_blank" rel="noopener noreferrer" style="color:#a59fc4;text-decoration:none;">quant-love</a> ·
<a href="https://proposal.vaked.dev/" target="_blank" rel="noopener noreferrer" style="color:#a59fc4;text-decoration:none;">proposal.vaked.dev</a> ·
<a href="https://pocoo.vaked.dev/" target="_blank" rel="noopener noreferrer" style="color:#a59fc4;text-decoration:none;">pocoo.vaked.dev</a> ·
<a href="https://axiomquant.org/" target="_blank" rel="noopener noreferrer" style="color:#a59fc4;text-decoration:none;">axiomquant.org</a> ·
<a href="https://portail.vaked.dev/" style="color:#62e6c9;text-decoration:none;">portail.vaked.dev</a> · <a href="status.html" style="color:#62e6c9;text-decoration:none;">✦ Telemetry Status</a>
</nav>
<div style="font-size:0.6rem;letter-spacing:0.18em;color:#7f7c99;margin-top:1.5rem;">the constellation · 0 + 1 · fine touch from within · vaked.dev</div>
</footer>
<iframe id="musicbg" src="https://music.vaked.dev/" title="music.vaked.dev — living background" aria-hidden="true" loading="lazy" referrerpolicy="no-referrer" style="position:fixed;inset:0;z-index:0;pointer-events:none;border:0;opacity:0.25;mix-blend-mode:screen"></iframe>
</body>
</html>