Skip to content

Commit 929d328

Browse files
committed
Add atomic.bond landing page
Static site in www/ matching Ploton design system: Inter + JetBrains Mono, light theme, minimal text-driven layout. Sections: agent.json, deposit box, magic links, request signing, JWT comparison table, security, install. Ready for Cloudflare Pages (static, no build step).
1 parent b156900 commit 929d328

2 files changed

Lines changed: 558 additions & 0 deletions

File tree

www/index.html

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>atomic — Domain identity for AI agents</title>
7+
<meta name="description" content="One binary gives your AI agent a domain-bound keypair, signed requests, an encrypted vault, and a deposit box for receiving secrets. No cloud, no accounts." />
8+
<link rel="preconnect" href="https://fonts.googleapis.com" />
9+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet" />
11+
<link rel="stylesheet" href="style.css" />
12+
</head>
13+
<body>
14+
15+
<!-- Nav -->
16+
<header class="nav">
17+
<nav class="nav-inner">
18+
<a href="/" class="nav-brand">atomic</a>
19+
<div class="nav-links">
20+
<a href="https://github.com/plotondev/atomic" class="nav-link">GitHub</a>
21+
<a href="https://github.com/plotondev/atomic#cli" class="nav-link">Docs</a>
22+
</div>
23+
</nav>
24+
</header>
25+
26+
<div class="nav-spacer"></div>
27+
28+
<main class="page">
29+
30+
<!-- Hero -->
31+
<h1 class="hero-heading">Domain identity for AI agents.</h1>
32+
33+
<p class="hero-body">
34+
Your agent gets an Ed25519 keypair bound to its domain, a public identity document at <code class="ic">/.well-known/agent.json</code>, an encrypted vault, and a deposit box for receiving secrets. One binary, ~4MB, runs on the same box as the agent.
35+
</p>
36+
37+
<pre class="code-block"><code>curl -fsSL atomic.bond/install | sh
38+
atomic init --domain fin.acme.com</code></pre>
39+
40+
<div class="cta-row">
41+
<a href="https://github.com/plotondev/atomic/releases" class="cta-btn">Download</a>
42+
<a href="https://github.com/plotondev/atomic" class="cta-link">View source</a>
43+
</div>
44+
45+
<!-- agent.json -->
46+
<hr class="section-rule" />
47+
48+
<h2 class="section-heading">agent.json</h2>
49+
<p class="section-body">
50+
Every agent publishes its public key at a well-known URL. The domain is the identity.
51+
</p>
52+
53+
<pre class="code-block"><code>$ curl https://fin.acme.com/.well-known/agent.json</code></pre>
54+
55+
<pre class="code-block"><code>{
56+
"v": 1,
57+
"id": "fin.acme.com",
58+
"name": "fin.acme.com",
59+
"public_key": "ed25519:m2UrN...",
60+
"status": "active",
61+
"deposit": "https://fin.acme.com/d/",
62+
"created_at": "2026-03-07T12:00:00Z"
63+
}</code></pre>
64+
65+
<p class="section-body muted">
66+
<code class="ic">GET /</code> redirects here. The public key is how other services verify this agent's signatures.
67+
</p>
68+
69+
<!-- Deposit box -->
70+
<hr class="section-rule" />
71+
72+
<h2 class="section-heading">Deposit box</h2>
73+
<p class="section-body">
74+
The agent needs an API key. Instead of pasting it into a <code class="ic">.env</code>:
75+
</p>
76+
77+
<pre class="code-block"><code><span class="code-comment"># Generate a one-time deposit URL</span>
78+
$ atomic deposit-url --label stripe_key --expires 10m
79+
https://fin.acme.com/d/eyJsYWJlbCI6...Rk4
80+
81+
<span class="code-comment"># Whoever has the secret POSTs it</span>
82+
$ curl -X POST ".../d/eyJsYWJlbCI6...Rk4" -d "sk_live_abc123"
83+
{"status":"deposited","label":"stripe_key"}
84+
85+
<span class="code-comment"># Agent reads it from the vault</span>
86+
$ atomic vault get stripe_key
87+
sk_live_abc123</code></pre>
88+
89+
<p class="section-body">
90+
The URL is Ed25519-signed, works exactly once (nonce-tracked), and caps out at 24 hours. The secret is AES-256-GCM encrypted before it hits disk.
91+
</p>
92+
93+
<pre class="code-block"><code><span class="code-comment"># Use secrets at runtime — no .env files</span>
94+
curl -H "Authorization: Bearer $(atomic vault get stripe_key)" \
95+
https://api.stripe.com/v1/charges
96+
97+
export OPENAI_API_KEY=$(atomic vault get openai_key)
98+
python agent.py</code></pre>
99+
100+
<!-- Magic links -->
101+
<hr class="section-rule" />
102+
103+
<h2 class="section-heading">Magic links</h2>
104+
<p class="section-body">
105+
Domain verification, like DNS TXT records but over HTTP. A service gives the agent a code, the agent hosts it, the service checks.
106+
</p>
107+
108+
<pre class="code-block"><code>$ atomic magic-link host VERIFY_ABC123 --expires 5m
109+
https://fin.acme.com/m/VERIFY_ABC123
110+
111+
$ curl https://fin.acme.com/m/VERIFY_ABC123
112+
{"status":"verified","code":"VERIFY_ABC123"}</code></pre>
113+
114+
<p class="section-body muted">
115+
One-time use, gone after the first GET, expires in minutes.
116+
</p>
117+
118+
<!-- Request signing -->
119+
<hr class="section-rule" />
120+
121+
<h2 class="section-heading">Request signing</h2>
122+
<p class="section-body">
123+
Every outgoing request gets an Ed25519 signature. The receiving service verifies against the public key in <code class="ic">agent.json</code>.
124+
</p>
125+
126+
<pre class="code-block"><code>$ atomic sign -- curl -X POST https://partner.api.com/transfer \
127+
-d '{"amount": 5000}'
128+
129+
<span class="code-comment"># Adds headers: X-Agent-Id, X-Agent-Sig, X-Agent-Sig-Time</span></code></pre>
130+
131+
<p class="section-body">
132+
Verification on the receiving end:
133+
</p>
134+
135+
<pre class="code-block"><code><span class="code-comment"># Python — four lines, no SDK</span>
136+
agent = requests.get(f"https://{agent_id}/.well-known/agent.json").json()
137+
key_bytes = base64.b64decode(agent["public_key"].removeprefix("ed25519:"))
138+
pub_key = Ed25519PublicKey.from_public_bytes(key_bytes)
139+
pub_key.verify(base64.b64decode(signature), f"{sig_time}.{body}".encode())</code></pre>
140+
141+
<!-- Why not JWTs -->
142+
<hr class="section-rule" />
143+
144+
<h2 class="section-heading">Why not JWTs?</h2>
145+
<p class="section-body">
146+
When a human logs into a service, the service issues a token. The agent carries it around, sends it on every request, refreshes it when it expires. Agents don't need that. An agent with a keypair can prove itself on every request by signing it.
147+
</p>
148+
149+
<div class="table-wrap">
150+
<table class="comparison-table">
151+
<thead>
152+
<tr>
153+
<th></th>
154+
<th>Human (JWT)</th>
155+
<th>Agent (Atomic)</th>
156+
</tr>
157+
</thead>
158+
<tbody>
159+
<tr><td>Identity</td><td>email + password</td><td>domain (<code class="ic">fin.acme.com</code>)</td></tr>
160+
<tr><td>Signup</td><td>create account, get credentials</td><td>sign request + magic link</td></tr>
161+
<tr><td>Proof</td><td>service issues a JWT</td><td>agent signs every request</td></tr>
162+
<tr><td>Each request</td><td>send JWT, service checks it</td><td>send signature, service checks agent.json</td></tr>
163+
<tr><td>Expiry</td><td>token expires, re-auth</td><td>no token — signatures are stateless</td></tr>
164+
<tr><td>Revocation</td><td>service invalidates token</td><td>agent.json status &rarr; <code class="ic">revoked</code></td></tr>
165+
<tr><td>Storage</td><td>store token, handle refresh</td><td>private key on disk, nothing to refresh</td></tr>
166+
</tbody>
167+
</table>
168+
</div>
169+
170+
<p class="section-body muted">
171+
Performance-wise, JWT verification is a single HMAC check while Ed25519 verify costs more. But "more" here means microseconds, and the public key caches well. It's not where your latency lives.
172+
</p>
173+
174+
<!-- Security -->
175+
<hr class="section-rule" />
176+
177+
<h2 class="section-heading">Security</h2>
178+
<p class="section-body">
179+
Private key stored at 600 permissions, never leaves the box. Vault uses AES-256-GCM with a key derived from the private key via HKDF — separate from the signing key.
180+
</p>
181+
<p class="section-body">
182+
Deposit tokens are Ed25519-signed with a nonce and a 24h max TTL. Every failure returns 404 regardless of the reason, so you can't probe for valid tokens. Body size capped at 1MB.
183+
</p>
184+
<p class="section-body muted">
185+
All responses get <code class="ic">nosniff</code>, <code class="ic">no-store</code>, and <code class="ic">no-referrer</code> headers. HSTS (2-year max-age) when TLS is on. SQL is parameterized everywhere.
186+
</p>
187+
188+
<!-- Install -->
189+
<hr class="section-rule" />
190+
191+
<h2 class="section-heading">Install</h2>
192+
193+
<pre class="code-block"><code><span class="code-comment"># One-line install</span>
194+
curl -fsSL atomic.bond/install | sh
195+
196+
<span class="code-comment"># Or build from source</span>
197+
git clone https://github.com/plotondev/atomic.git
198+
cd atomic && cargo build --release</code></pre>
199+
200+
<p class="section-body">
201+
Binaries for Linux (x86_64, aarch64) and macOS (x86_64, Apple Silicon) on the <a href="https://github.com/plotondev/atomic/releases" class="body-link">releases page</a>.
202+
</p>
203+
204+
<!-- Footer CTA -->
205+
<hr class="section-rule" />
206+
207+
<div class="cta-row">
208+
<a href="https://github.com/plotondev/atomic/releases" class="cta-btn">Download</a>
209+
<a href="https://github.com/plotondev/atomic" class="cta-link">View source</a>
210+
</div>
211+
212+
<p class="contact">
213+
MIT License. Questions? <a href="mailto:hello@ploton.ai" class="body-link">hello@ploton.ai</a>
214+
</p>
215+
216+
</main>
217+
218+
</body>
219+
</html>

0 commit comments

Comments
 (0)