592 lines
40 KiB
Cheetah
592 lines
40 KiB
Cheetah
{{define "index"}}
|
|
<!-- Hero -->
|
|
<div class="container hero-split">
|
|
<div>
|
|
<p class="label accent mb-6">George Orwell — 1984</p>
|
|
<h1 class="mb-6">"If you want to keep a secret, you must also hide it from yourself."</h1>
|
|
<p class="lead mb-6">We did. Your Identity Encryption key is derived in your browser from your WebAuthn authenticator — fingerprint, face, or hardware key. Our servers have never seen it. They could not decrypt your private fields even if they wanted to. Or anybody else.</p>
|
|
<div class="btn-row">
|
|
<a href="/hosted" class="btn btn-primary">Get hosted — $12/yr</a>
|
|
<a href="/install" class="btn btn-ghost">Self-host free →</a>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<!-- Hero SVG: Credential/Identity encryption diagram -->
|
|
<svg viewBox="0 0 480 380" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<!-- Background -->
|
|
<rect x="0" y="0" width="480" height="380" rx="12" fill="#f5f5f5"/>
|
|
|
|
<!-- Top labels -->
|
|
<text x="130" y="35" font-family="JetBrains Mono, monospace" font-size="11" fill="#737373" text-anchor="middle">AI Agent</text>
|
|
<text x="350" y="35" font-family="JetBrains Mono, monospace" font-size="11" fill="#737373" text-anchor="middle">You only</text>
|
|
|
|
<!-- Arrows -->
|
|
<path d="M130 42 L130 58" stroke="#22C55E" stroke-width="1.5" marker-end="url(#arrowGreen)"/>
|
|
<path d="M350 42 L350 58" stroke="#EF4444" stroke-width="1.5" marker-end="url(#arrowRed)"/>
|
|
<defs>
|
|
<marker id="arrowGreen" markerWidth="8" markerHeight="6" refX="4" refY="3" orient="auto"><path d="M0,0 L4,3 L0,6" fill="none" stroke="#22C55E" stroke-width="1.5"/></marker>
|
|
<marker id="arrowRed" markerWidth="8" markerHeight="6" refX="4" refY="3" orient="auto"><path d="M0,0 L4,3 L0,6" fill="none" stroke="#EF4444" stroke-width="1.5"/></marker>
|
|
</defs>
|
|
|
|
<!-- Credential Encryption Column (AI-readable) -->
|
|
<rect x="30" y="65" width="200" height="260" rx="8" fill="none" stroke="#22C55E" stroke-width="1" stroke-opacity="0.3"/>
|
|
<rect x="30" y="65" width="200" height="30" rx="8" fill="#22C55E" fill-opacity="0.1"/>
|
|
<text x="130" y="85" font-family="JetBrains Mono, monospace" font-size="12" fill="#22C55E" text-anchor="middle" font-weight="600">Credential — AI can read</text>
|
|
|
|
<!-- L2 items -->
|
|
<g>
|
|
<rect x="50" y="115" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="80" y="138" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">github_token</text>
|
|
<circle cx="192" cy="133" r="8" fill="#22C55E" fill-opacity="0.15"/>
|
|
<path d="M188 133 L190.5 135.5 L196 130" stroke="#22C55E" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="50" y="163" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="80" y="186" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">ssh_key</text>
|
|
<circle cx="192" cy="181" r="8" fill="#22C55E" fill-opacity="0.15"/>
|
|
<path d="M188 181 L190.5 183.5 L196 178" stroke="#22C55E" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="50" y="211" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="80" y="234" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">totp_github</text>
|
|
<circle cx="192" cy="229" r="8" fill="#22C55E" fill-opacity="0.15"/>
|
|
<path d="M188 229 L190.5 231.5 L196 226" stroke="#22C55E" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="50" y="259" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="80" y="282" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">oauth_slack</text>
|
|
<circle cx="192" cy="277" r="8" fill="#22C55E" fill-opacity="0.15"/>
|
|
<path d="M188 277 L190.5 279.5 L196 274" stroke="#22C55E" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
|
|
<!-- Identity Encryption Column (only you) -->
|
|
<rect x="250" y="65" width="200" height="260" rx="8" fill="none" stroke="#EF4444" stroke-width="1" stroke-opacity="0.3"/>
|
|
<rect x="250" y="65" width="200" height="30" rx="8" fill="#EF4444" fill-opacity="0.1"/>
|
|
<text x="350" y="85" font-family="JetBrains Mono, monospace" font-size="12" fill="#EF4444" text-anchor="middle" font-weight="600">Identity — only you</text>
|
|
|
|
<!-- L3 items -->
|
|
<g>
|
|
<rect x="270" y="115" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="300" y="138" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">credit_card</text>
|
|
<rect x="404" y="125" width="16" height="16" rx="3" fill="#EF4444" fill-opacity="0.15"/>
|
|
<path d="M409 131 L409 135 M412 131 L412 135 M407 133 L407 129 Q407 127 413 127 L412 127 Q414 127 418 129 L414 133 Z" stroke="#EF4444" stroke-width="1.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="270" y="163" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="300" y="186" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">cvv</text>
|
|
<rect x="404" y="173" width="16" height="16" rx="3" fill="#EF4444" fill-opacity="0.15"/>
|
|
<path d="M409 179 L409 183 M412 179 L412 183 M407 181 L407 177 Q407 175 413 175 L412 175 Q414 175 418 177 L414 181 Z" stroke="#EF4444" stroke-width="1.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="270" y="211" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="300" y="234" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">passport</text>
|
|
<rect x="404" y="221" width="16" height="16" rx="3" fill="#EF4444" fill-opacity="0.15"/>
|
|
<path d="M409 227 L409 231 M412 227 L412 231 M407 229 L407 225 Q407 223 413 223 L412 223 Q414 223 418 225 L414 229 Z" stroke="#EF4444" stroke-width="1.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
<g>
|
|
<rect x="270" y="259" width="160" height="36" rx="6" fill="#ffffff"/>
|
|
<text x="300" y="282" font-family="JetBrains Mono, monospace" font-size="11" fill="#525252">ssn</text>
|
|
<rect x="404" y="269" width="16" height="16" rx="3" fill="#EF4444" fill-opacity="0.15"/>
|
|
<path d="M409 275 L409 279 M412 275 L412 279 M407 277 L407 273 Q407 271 413 271 L412 271 Q414 271 418 273 L414 277 Z" stroke="#EF4444" stroke-width="1.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</g>
|
|
|
|
<!-- Center vault icon -->
|
|
<rect x="224" y="340" width="32" height="28" rx="4" fill="#f5f5f5" stroke="#737373" stroke-width="1"/>
|
|
<circle cx="240" cy="352" r="3" fill="none" stroke="#737373" stroke-width="1"/>
|
|
<line x1="240" y1="355" x2="240" y2="360" stroke="#737373" stroke-width="1"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Two problems -->
|
|
<div class="section container">
|
|
<p class="label accent mb-4">Credential issuance & password management</p>
|
|
<h2 class="mb-6">Two problems. One product.</h2>
|
|
<div class="grid-2 mb-4">
|
|
<div class="card">
|
|
<h3 class="mb-3">AI agents need credentials</h3>
|
|
<p>Your agents deploy code, rotate keys, complete 2FA — but current password managers either give them everything or nothing. Clavitor issues scoped credentials to each agent. No vault browsing. No discovery.</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3 class="mb-3">Credentials need real encryption</h3>
|
|
<p>Every password manager encrypts with a master password. When that password is weak — or stolen — everything falls. Clavitor derives keys from your hardware. No password to crack. No backup to brute-force.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- The Problem -->
|
|
<div class="section container">
|
|
<h2 class="mb-4">The problem</h2>
|
|
<p class="lead mb-8">Every password manager was built before AI agents existed. Now they need to catch up.</p>
|
|
<div class="grid-3">
|
|
<div class="card card-hover">
|
|
<div class="feature-icon red"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/></svg></div>
|
|
<h3 class="mb-3">All-or-nothing is broken</h3>
|
|
<p>All others give your AI agent access to everything in your vault, or nothing at all. Your AI needs your GitHub token — it shouldn't also see your passport number.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon red"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg></div>
|
|
<h3 class="mb-3">Policy isn't security</h3>
|
|
<p>"AI-safe" vaults still decrypt everything server-side. If the server can read it, it's not truly private. Math beats policy every time.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon red"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg></div>
|
|
<h3 class="mb-3">Agents need credentials — and 2FA</h3>
|
|
<p>Your AI can't log in, pass two-factor, or rotate keys without access. <span class="vaultname">clavitor</span> lets it do all three — without exposing your credit card to the same pipeline.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- How it works -->
|
|
<div class="section container">
|
|
<p class="label mb-4">How it works</p>
|
|
<h2 class="mb-6">"Your assistant can book your flights.<br><span class="gradient-text">Not read your diary.</span>"</h2>
|
|
<p class="lead mb-8">Every field is encrypted. But some get a second lock. That second key is derived from your WebAuthn authenticator and only exists in your browser. We hold the safe. Only you hold that key.</p>
|
|
<div class="grid-2">
|
|
<div class="card alt">
|
|
<span class="badge accent mb-4">Credential Encryption</span>
|
|
<h3 class="mb-3">AI-readable</h3>
|
|
<p class="mb-4">Encrypted at rest, decryptable by the vault server. Your AI agent accesses these via the CLI.</p>
|
|
<ul class="checklist">
|
|
<li>API keys & tokens</li>
|
|
<li>SSH keys</li>
|
|
<li>TOTP 2FA codes — AI generates them for you</li>
|
|
<li>OAuth tokens</li>
|
|
<li>Structured notes</li>
|
|
</ul>
|
|
</div>
|
|
<div class="card red">
|
|
<span class="badge red mb-4">Identity Encryption</span>
|
|
<h3 class="mb-3">Your device only</h3>
|
|
<p class="mb-4">Encrypted client-side with WebAuthn PRF. The server never sees the plaintext. Ever.</p>
|
|
<ul class="checklist red">
|
|
<li>Credit card numbers</li>
|
|
<li>CVV</li>
|
|
<li>Passport & SSN</li>
|
|
<li>Private signing keys</li>
|
|
<li>Private notes</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Features -->
|
|
<div class="section container">
|
|
<h2 class="mb-4">Built different</h2>
|
|
<p class="lead mb-8">Not another password manager with an AI checkbox. The architecture is the feature.</p>
|
|
<div class="grid-3">
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16"/></svg></div>
|
|
<h3 class="mb-3">Field-level AI visibility</h3>
|
|
<p>Each field has its own encryption tier. Your AI reads the username, not the CVV. Same entry, different access.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 11c0 3.517-1.009 6.799-2.753 9.571m-3.44-2.04l.054-.09A13.916 13.916 0 008 11a4 4 0 118 0c0 1.017-.07 2.019-.203 3m-2.118 6.844A21.88 21.88 0 0015.171 17m3.839 1.132c.645-2.266.99-4.659.99-7.132A8 8 0 008 4.07M3 15.364c.64-1.319 1-2.8 1-4.364 0-1.457.39-2.823 1.07-4"/></svg></div>
|
|
<h3 class="mb-3">WebAuthn PRF</h3>
|
|
<p>Identity Encryption uses WebAuthn PRF — a cryptographic key derived from your WebAuthn authenticator — fingerprint, face, or hardware key. Math, not policy. We literally cannot decrypt it.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/></svg></div>
|
|
<h3 class="mb-3">API keys as first-class citizens</h3>
|
|
<p>The only vault with a dedicated API key category — agent-accessible (L2) and visually distinct. Hosted plans auto-detect API keys on import. Your agent fetches the API key. It never sees your passport.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg></div>
|
|
<h3 class="mb-3">Scoped agent tokens</h3>
|
|
<p>Create separate tokens per agent. Each token sees only its designated entries. Compromise one, the rest stay clean.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"/></svg></div>
|
|
<h3 class="mb-3">One binary, one file</h3>
|
|
<p>No Docker. No Postgres. No Redis. One Go binary, one SQLite file. Runs on a Raspberry Pi. Runs on a $4/month VPS.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<div class="feature-icon"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg></div>
|
|
<h3 class="mb-3">Upgrade from anything</h3>
|
|
<p>Import from 14 password managers and browsers. Every field mapped, every type preserved, double-encrypted on arrival. <a href="/upgrade">See all sources →</a></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Multi-agent -->
|
|
<div class="section container">
|
|
<div class="grid-2">
|
|
<div>
|
|
<h2 class="mb-4">10 agents.<br><span class="gradient-text">Each gets exactly what it needs.</span></h2>
|
|
<p class="lead mb-6">Create scoped CLI tokens per agent. One compromised agent exposes one scope — not your entire vault.</p>
|
|
<p class="mb-4">Why not MCP? Because credentials are encrypted in the vault — they need to be decrypted locally by the CLI. An MCP server can't do that. The CLI decrypts on your machine, returns the plaintext, and nothing sensitive ever passes through a third-party protocol layer.</p>
|
|
<div class="code-block">
|
|
<p class="code-label">Agent workflow</p>
|
|
<pre><span class="comment"># Agent fetches exactly what it's scoped to</span>
|
|
<span class="prompt">$</span> clavitor-cli get "GitHub Deploy" --field password
|
|
ghp_a3f8...</pre>
|
|
</div>
|
|
<div class="code-block mt-4">
|
|
<p class="code-label">Claude Code</p>
|
|
<pre><span class="comment"># Install the skill — Claude Code learns your vault</span>
|
|
<span class="prompt">$</span> clavitor-cli skill > ~/.claude/skills/clavitor.md
|
|
|
|
<span class="comment"># Then just ask:</span>
|
|
<span class="comment"># "get me the AWS credentials"</span>
|
|
<span class="comment"># "store this API key as 'Stripe Prod'"</span></pre>
|
|
</div>
|
|
<p class="mt-4 text-sm"><a href="/developers">See all languages and platforms →</a></p>
|
|
</div>
|
|
<div>
|
|
<!-- Multi-agent SVG -->
|
|
<svg viewBox="0 0 400 360" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<!-- Center vault -->
|
|
<rect x="160" y="140" width="80" height="80" rx="12" fill="#f5f5f5" stroke="#737373" stroke-width="1.5"/>
|
|
<rect x="175" y="152" width="20" height="20" rx="0" fill="#0A0A0A"/>
|
|
<text x="200" y="190" font-family="IBM Plex Sans, sans-serif" font-size="10" fill="#0A0A0A" text-anchor="middle" font-weight="700" letter-spacing="0.25em">CLAVITOR</text>
|
|
|
|
<!-- Agent 1 — dev -->
|
|
<circle cx="80" cy="60" r="32" fill="#0A0A0A" fill-opacity="0.08" stroke="#0A0A0A" stroke-width="1"/>
|
|
<text x="80" y="56" font-family="JetBrains Mono, monospace" font-size="9" fill="#0A0A0A" text-anchor="middle">Agent 1</text>
|
|
<text x="80" y="68" font-family="JetBrains Mono, monospace" font-size="8" fill="#737373" text-anchor="middle">dev</text>
|
|
<line x1="108" y1="80" x2="165" y2="145" stroke="#0A0A0A" stroke-width="1" stroke-opacity="0.4" stroke-dasharray="4 3"/>
|
|
|
|
<!-- Agent 2 — social -->
|
|
<circle cx="320" cy="60" r="32" fill="#0A0A0A" fill-opacity="0.08" stroke="#0A0A0A" stroke-width="1"/>
|
|
<text x="320" y="56" font-family="JetBrains Mono, monospace" font-size="9" fill="#0A0A0A" text-anchor="middle">Agent 2</text>
|
|
<text x="320" y="68" font-family="JetBrains Mono, monospace" font-size="8" fill="#737373" text-anchor="middle">social</text>
|
|
<line x1="292" y1="80" x2="235" y2="145" stroke="#0A0A0A" stroke-width="1" stroke-opacity="0.4" stroke-dasharray="4 3"/>
|
|
|
|
<!-- Agent 3 — finance -->
|
|
<circle cx="50" cy="220" r="32" fill="#0A0A0A" fill-opacity="0.08" stroke="#0A0A0A" stroke-width="1"/>
|
|
<text x="50" y="216" font-family="JetBrains Mono, monospace" font-size="9" fill="#0A0A0A" text-anchor="middle">Agent 3</text>
|
|
<text x="50" y="228" font-family="JetBrains Mono, monospace" font-size="8" fill="#737373" text-anchor="middle">finance</text>
|
|
<line x1="78" y1="204" x2="164" y2="190" stroke="#0A0A0A" stroke-width="1" stroke-opacity="0.4" stroke-dasharray="4 3"/>
|
|
|
|
<!-- Agent 4 — infra -->
|
|
<circle cx="350" cy="220" r="32" fill="#0A0A0A" fill-opacity="0.08" stroke="#0A0A0A" stroke-width="1"/>
|
|
<text x="350" y="216" font-family="JetBrains Mono, monospace" font-size="9" fill="#0A0A0A" text-anchor="middle">Agent 4</text>
|
|
<text x="350" y="228" font-family="JetBrains Mono, monospace" font-size="8" fill="#737373" text-anchor="middle">infra</text>
|
|
<line x1="322" y1="204" x2="236" y2="190" stroke="#0A0A0A" stroke-width="1" stroke-opacity="0.4" stroke-dasharray="4 3"/>
|
|
|
|
<!-- Agent 5 — deploy -->
|
|
<circle cx="200" cy="330" r="32" fill="#0A0A0A" fill-opacity="0.08" stroke="#0A0A0A" stroke-width="1"/>
|
|
<text x="200" y="326" font-family="JetBrains Mono, monospace" font-size="9" fill="#0A0A0A" text-anchor="middle">Agent 5</text>
|
|
<text x="200" y="338" font-family="JetBrains Mono, monospace" font-size="8" fill="#737373" text-anchor="middle">deploy</text>
|
|
<line x1="200" y1="298" x2="200" y2="220" stroke="#0A0A0A" stroke-width="1" stroke-opacity="0.4" stroke-dasharray="4 3"/>
|
|
|
|
<!-- Scope labels -->
|
|
<rect x="10" y="98" width="140" height="20" rx="4" fill="#ffffff"/>
|
|
<text x="80" y="112" font-family="JetBrains Mono, monospace" font-size="7.5" fill="#737373" text-anchor="middle">github ssh gitlab</text>
|
|
|
|
<rect x="250" y="98" width="140" height="20" rx="4" fill="#ffffff"/>
|
|
<text x="320" y="112" font-family="JetBrains Mono, monospace" font-size="7.5" fill="#737373" text-anchor="middle">twitter slack discord</text>
|
|
|
|
<rect x="0" y="256" width="100" height="20" rx="4" fill="#ffffff"/>
|
|
<text x="50" y="270" font-family="JetBrains Mono, monospace" font-size="7.5" fill="#737373" text-anchor="middle">stripe plaid</text>
|
|
|
|
<rect x="300" y="256" width="100" height="20" rx="4" fill="#ffffff"/>
|
|
<text x="350" y="270" font-family="JetBrains Mono, monospace" font-size="7.5" fill="#737373" text-anchor="middle">aws k8s docker</text>
|
|
|
|
<rect x="150" y="296" width="100" height="16" rx="4" fill="#ffffff"/>
|
|
<text x="200" y="308" font-family="JetBrains Mono, monospace" font-size="7.5" fill="#737373" text-anchor="middle">vercel netlify</text>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Access Methods -->
|
|
<div class="section container">
|
|
<h2 class="mb-4">Your agent and you — same vault, right access</h2>
|
|
<p class="lead mb-8">Four ways in. Each one designed for a different context. All pointing at the same encrypted store.</p>
|
|
<div class="grid-2">
|
|
<div class="card card-hover">
|
|
<p class="label accent mb-3">CLI</p>
|
|
<h3 class="mb-2">For AI agents</h3>
|
|
<p>Agents call the CLI to fetch credentials — scoped per agent. Each agent sees only what it's been granted. No vault browsing, no discovery.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<p class="label accent mb-3">Extension</p>
|
|
<h3 class="mb-2">For humans in a browser</h3>
|
|
<p>Autofill passwords, generate 2FA codes inline, and unlock Identity fields with your authenticator — without leaving the page you're on.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<p class="label accent mb-3">CLI</p>
|
|
<h3 class="mb-2">For terminal workflows</h3>
|
|
<p>Pipe credentials directly into scripts and CI pipelines. <code>vault get github.token</code> — done.</p>
|
|
</div>
|
|
<div class="card card-hover">
|
|
<p class="label accent mb-3">API</p>
|
|
<h3 class="mb-2">For everything else</h3>
|
|
<p>REST API with scoped tokens. Give your deployment pipeline read access to staging keys. Nothing else.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Why this matters -->
|
|
<div class="section container">
|
|
<p class="label red mb-4">Why this matters</p>
|
|
<h2 class="mb-4">Breached in 2022. Still bleeding in <script>document.write(new Date().getFullYear())</script>.</h2>
|
|
<p class="lead mb-8">In 2022, LastPass lost encrypted vault backups. Each vault was encrypted with the customer's master password. Three years later, attackers are still cracking them — weak passwords first, stronger ones next. The FBI traced $150M in crypto theft to that single breach. But crypto is just the visible damage — the same vaults held bank logins, corporate VPN credentials, medical portals, and tax accounts.</p>
|
|
<div class="grid-3 mb-8">
|
|
<div class="card">
|
|
<div style="font-size:2rem;font-weight:800;color:var(--brand-red);margin-bottom:8px">$150M+</div>
|
|
<p>Confirmed crypto stolen from a single breach. FBI-traced. Still growing. <a href="https://krebsonsecurity.com/2025/03/feds-link-150m-cyberheist-to-2022-lastpass-hacks/" target="_blank" rel="noopener" class="text-accent">Krebs on Security ↗</a></p>
|
|
</div>
|
|
<div class="card">
|
|
<div style="font-size:2rem;font-weight:800;color:var(--brand-red);margin-bottom:8px" id="breach-years">3 years</div>
|
|
<script>document.getElementById('breach-years').textContent=((new Date).getFullYear()-2022)+' years';</script>
|
|
<p>Thefts still ongoing. The encryption was per-customer — but the key was a password. Passwords get cracked. <a href="https://securityaffairs.com/186191/digital-id/stolen-lastpass-backups-enable-crypto-theft-through-2025.html" target="_blank" rel="noopener" class="text-accent">Security Affairs ↗</a></p>
|
|
</div>
|
|
<div class="card">
|
|
<div style="font-size:2rem;font-weight:800;color:var(--brand-red);margin-bottom:8px">forever</div>
|
|
<p>Brute-forcing a Clavitor hardware key at a trillion guesses per second would take a trillion × a trillion × a trillion × a trillion times longer than the universe has existed. That's not a figure of speech. That's the math.</p>
|
|
</div>
|
|
</div>
|
|
<p class="mb-4"><strong>Clavitor's answer:</strong> {{len .Pops}} regions — every vault is an isolated database, not a row in a shared table. Every credential and identity field has its own encryption key derived from your WebAuthn authenticator — fingerprint, face, YubiKey, or any FIDO2 device. Not a password you chose. Not a password you could choose. A key that never existed on any server, never existed in any backup, and cannot be brute-forced because it was never a string of characters to begin with.</p>
|
|
<p class="mb-4"><strong>That power comes with responsibility.</strong> Always register at least two devices (phone + laptop). Better yet: print your recovery key, protect it with a PIN, and store it somewhere outside your home. If you lose all your devices, that printout is your only way back in. We can't help you — by design.</p>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- The competition -->
|
|
<div class="section container">
|
|
<p class="label mb-4">The competition</p>
|
|
<h2 class="mb-4">We listened. And addressed them all.</h2>
|
|
<p class="lead mb-8">Real complaints from real users — about 1Password, Bitwarden, and LastPass. Pulled from forums, GitHub issues, and Hacker News. Not cherry-picked from our own users.</p>
|
|
|
|
<div class="grid-3">
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">1PASSWORD — Community Forum</p>
|
|
<p><em>"The web extensions are laughably bad at this point. This has been going on for months. They either won't fill, wont' unlock, or just plain won't do anything (even clicking extension icon). It's so bad"</em></p>
|
|
<p class="mt-2"><a href="https://www.1password.community/discussions/1password/constantly-being-asked-to-unlock-with-password/90511" target="_blank" rel="noopener">— notnotjake, April 2024 ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: No desktop app dependency. The extension talks directly to the local vault binary — no IPC, no sync, no unlock chains.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">BITWARDEN — GitHub Issues</p>
|
|
<p><em>"Every single website loads slower. From Google, up to social media websites like Reddit, Instagram, X up to websites like example.com. Even scrolling and animation stutters sometimes. javascript heavy websites like X, Instagram, Reddit etc. become extremely sluggish when interacting with buttons. So for me the Bitwarden browser extension is unusable. It interferes with my browsing experience like malware."</em></p>
|
|
<p class="mt-2"><a href="https://github.com/bitwarden/clients/issues/11077" target="_blank" rel="noopener">— julianw1011, 2024 ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: Zero content scripts. The extension injects nothing into pages — it fills via the browser autofill API only when you ask.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">LASTPASS — Hacker News</p>
|
|
<p><em>"The fact they're drip-feeding how bad this breach actually was is terrible enough... Personally I'm never touching them again."</em></p>
|
|
<p class="mt-2"><a href="https://news.ycombinator.com/item?id=34516275" target="_blank" rel="noopener">— intunderflow, January 2023 ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: Self-host or use hosted with L3 encryption — we mathematically cannot read your private fields. No vault data to breach.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">1PASSWORD — Community Forum</p>
|
|
<p><em>"Since doing so, it asks me to enter my password every 10 minutes or so in the chrome extension"</em></p>
|
|
<p class="mt-2"><a href="https://www.1password.community/discussions/1password/why-does-the-chrome-extension-keep-asking-for-my-password-every-10-mins-rather-t/74253" target="_blank" rel="noopener">— Anonymous (Former Member), November 2022 ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: WebAuthn-first. Your authenticator is the primary unlock. Session lives locally — no server-side expiry forcing re-auth.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">BITWARDEN — Community Forums</p>
|
|
<p><em>"the password not only auto-filled in the password field, but also auto-filled in reddit's search box!"</em></p>
|
|
<p class="mt-2"><em>"if autofill has the propensity at times to put an entire password in plain text in a random field, autofill seems like more risk than it's worth."</em></p>
|
|
<p class="mt-2"><a href="https://community.bitwarden.com/t/auto-fill-is-pasting-password-in-website-search-box/44045" target="_blank" rel="noopener">— xru1nib5 ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: LLM field mapping. The extension reads the form, asks the model which field is which — fills by intent, not by CSS selector.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card red">
|
|
<p class="label red mb-3">BITWARDEN — Community Forums</p>
|
|
<p><em>"Bitwarden REFUSES to autofill the actual password saved for a given site or app...and instead fills an old password. It simply substitutes the OLD password for the new one that is plainly saved in the vault."</em></p>
|
|
<p class="mt-2"><a href="https://community.bitwarden.com/t/autofill-is-wrong-saved-password-is-right/32090" target="_blank" rel="noopener">— gentlezacharias ↗</a></p>
|
|
<hr class="divider mt-4 mb-4">
|
|
<ul class="checklist">
|
|
<li><span class="vaultname">clavitor</span>: LLM field mapping matches by intent. Entries are indexed by URL — the right credential for the right site, every time.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<p class="mt-8">All quotes verbatim from public posts. URLs verified. <a href="/sources">View sources →</a></p>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Hosted CTA -->
|
|
<div class="section container">
|
|
<h2 class="mb-4">Your vault needs to be everywhere you are.</h2>
|
|
<p class="lead mb-3">A password manager that only works on your home network isn't a password manager. Your laptop moves. Your phone moves. Your browser extension needs your vault at the coffee shop, on the plane, at the client's office.</p>
|
|
<p class="mb-3">Self-hosting that means a server with a public IP, DNS, TLS certificates, uptime monitoring, and backups. That's not a weekend project — that's infrastructure.</p>
|
|
<p class="mb-8">We run <span class="vaultname">clavitor</span> across {{len .Pops}} regions on every continent. $12/yr. Your Identity Encryption keys never leave your browser — we mathematically cannot read your private fields.</p>
|
|
<div class="btn-row">
|
|
<a href="/hosted" class="btn btn-primary">Get hosted →</a>
|
|
<a href="/install" class="btn btn-ghost">Self-host anyway</a>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="divider">
|
|
|
|
<!-- Quick install -->
|
|
<div class="section container">
|
|
<h2 class="mb-4">Up and running in 30 seconds</h2>
|
|
<p class="lead mb-8">One command. No dependencies.</p>
|
|
<div class="code-block mb-6">
|
|
<p class="code-label">Terminal</p>
|
|
<div><span class="comment"># Self-host in 30 seconds</span></div>
|
|
<div><span class="prompt">$</span> curl -fsSL clavitor.ai/install.sh | sh</div>
|
|
<div><span class="prompt">$</span> clavitor</div>
|
|
<div class="comment"># Running on http://localhost:1984</div>
|
|
</div>
|
|
<div class="code-block">
|
|
<p class="code-label">Agent access — scoped, encrypted</p>
|
|
<pre><span class="comment"># Initialize the agent (one-time, token from web UI)</span>
|
|
<span class="prompt">$</span> clavitor-cli init <setup-token>
|
|
|
|
<span class="comment"># Agent fetches only what it's scoped to</span>
|
|
<span class="prompt">$</span> clavitor-cli get "Vercel" --field password
|
|
tV3r...</pre>
|
|
</div>
|
|
<p class="mt-4"><a href="/install" class="btn btn-accent">Full install guide →</a></p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "index-script"}}
|
|
<script>
|
|
(function() {
|
|
const W = 1000, H = 460;
|
|
function project(lon, lat) {
|
|
const latR = Math.min(Math.abs(lat), 85) * Math.PI / 180 * (lat < 0 ? -1 : 1);
|
|
const miller = 1.25 * Math.log(Math.tan(Math.PI/4 + 0.4*latR));
|
|
const maxMiller = 1.25 * Math.log(Math.tan(Math.PI/4 + 0.4*80*Math.PI/180));
|
|
const x = (lon + 180) / 360 * W;
|
|
const y = H/2 - (miller / (2*maxMiller)) * H;
|
|
return [Math.round(x*10)/10, Math.round(y*10)/10];
|
|
}
|
|
|
|
function addVisitorDot(lat, lon, city) {
|
|
const svg = document.getElementById('worldmap');
|
|
if (!svg) return;
|
|
const [x, y] = project(lon, lat);
|
|
const ns = 'http://www.w3.org/2000/svg';
|
|
|
|
// Pulse ring
|
|
const ring = document.createElementNS(ns, 'circle');
|
|
ring.setAttribute('cx', x); ring.setAttribute('cy', y);
|
|
ring.setAttribute('r', '3'); ring.setAttribute('fill', 'none');
|
|
ring.setAttribute('stroke', '#0A0A0A'); ring.setAttribute('stroke-width', '1.5');
|
|
const a1 = document.createElementNS(ns, 'animate');
|
|
a1.setAttribute('attributeName', 'r'); a1.setAttribute('values', '3;16;3');
|
|
a1.setAttribute('dur', '2s'); a1.setAttribute('repeatCount', 'indefinite');
|
|
const a2 = document.createElementNS(ns, 'animate');
|
|
a2.setAttribute('attributeName', 'stroke-opacity'); a2.setAttribute('values', '0.8;0;0.8');
|
|
a2.setAttribute('dur', '2s'); a2.setAttribute('repeatCount', 'indefinite');
|
|
ring.appendChild(a1); ring.appendChild(a2);
|
|
|
|
// Dot
|
|
const dot = document.createElementNS(ns, 'circle');
|
|
dot.setAttribute('cx', x); dot.setAttribute('cy', y);
|
|
dot.setAttribute('r', '4'); dot.setAttribute('fill', '#0A0A0A');
|
|
dot.setAttribute('stroke', '#ffffff'); dot.setAttribute('stroke-width', '1.5');
|
|
|
|
// Label
|
|
const label = document.createElementNS(ns, 'text');
|
|
label.setAttribute('x', x); label.setAttribute('y', y + 15);
|
|
label.setAttribute('font-family', 'Inter,sans-serif');
|
|
label.setAttribute('font-size', '10');
|
|
label.setAttribute('fill', '#0A0A0A');
|
|
label.setAttribute('text-anchor', 'middle');
|
|
label.setAttribute('font-weight', '500');
|
|
label.textContent = city || 'You';
|
|
|
|
svg.appendChild(ring);
|
|
svg.appendChild(dot);
|
|
svg.appendChild(label);
|
|
}
|
|
|
|
function handleGeoData(d) {
|
|
if (!d.latitude || !d.longitude) return;
|
|
addVisitorDot(d.latitude, d.longitude, d.city || 'You');
|
|
|
|
const grid = document.getElementById('dc-grid');
|
|
if (!grid) return;
|
|
|
|
// Build visitor card
|
|
const flag = d.country_code ? d.country_code.toUpperCase().split('').map(c =>
|
|
String.fromCodePoint(c.charCodeAt(0) + 127397)).join('') : '📍';
|
|
const label = [d.city, d.country_name].filter(Boolean).join(', ') || 'Your location';
|
|
const region = d.region || '';
|
|
|
|
const card = document.createElement('div');
|
|
card.className = 'visitor-card card-hover';
|
|
card.setAttribute('data-lon', d.longitude);
|
|
card.innerHTML = `
|
|
<div class="visitor-flag">${flag}</div>
|
|
<div class="visitor-label">${label}</div>
|
|
<div class="visitor-region">${region}</div>
|
|
<div class="visitor-status">
|
|
<span class="visitor-dot"></span>You are here
|
|
</div>`;
|
|
|
|
// Expand to 5 columns
|
|
grid.style.gridTemplateColumns = "repeat(5,1fr)";
|
|
|
|
// Insert at correct longitude position
|
|
const cards = [...grid.children];
|
|
const insertBefore = cards.find(c => parseFloat(c.getAttribute('data-lon')) > d.longitude);
|
|
if (insertBefore) grid.insertBefore(card, insertBefore);
|
|
else grid.appendChild(card);
|
|
|
|
|
|
}
|
|
|
|
fetch('/geo')
|
|
.then(r => r.json())
|
|
.then(d => {
|
|
if (d.latitude) {
|
|
handleGeoData(d);
|
|
} else if (d.private && navigator.geolocation) {
|
|
navigator.geolocation.getCurrentPosition(pos => {
|
|
const lat = pos.coords.latitude, lon = pos.coords.longitude;
|
|
// Reverse geocode via open-meteo's free geocoding isn't ideal;
|
|
// use bigdatacloud free reverse geocode — no key, no signup
|
|
fetch(`/geo?lat=${lat}&lon=${lon}`)
|
|
.then(r => r.json())
|
|
.then(g => handleGeoData({
|
|
latitude: lat, longitude: lon,
|
|
city: g.city || 'You',
|
|
region: g.region || '',
|
|
country_name: g.country_name || '',
|
|
country_code: g.country_code || ''
|
|
}))
|
|
.catch(() => handleGeoData({ latitude: lat, longitude: lon,
|
|
city: 'You', region: '', country_name: '', country_code: '' }));
|
|
}, () => {});
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
})();
|
|
</script>
|
|
{{end}}
|