Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
Commit10d172bunknown_key

feat(vercel): ship static splash at gluecron.com — Fly.io app untouched

feat(vercel): ship static splash at gluecron.com — Fly.io app untouched

Craig wants gluecron.com live on Vercel now, with the full Hono/Bun/Neon
server following onto Crontech once Crontech's self-host is complete
(per the post-self-host onboarding directive).

Scope: additive only.
- public/index.html — standalone landing page. Copy lifted from
  src/views/landing.tsx verbatim (hero, 9 feature cards, vs-GitHub
  comparison, 3-step how-it-works, final CTA band). Inlines the same
  --bg/--text/--border dark-theme CSS variables the real app uses so
  the brand stays consistent when visitors eventually hit the Fly
  deployment. Fully self-contained — zero JS, zero runtime deps.
- vercel.json — framework: null, no build/install, outputDirectory:
  public. Tells Vercel "this is a static site, just serve public/"
  so it does not try to `bun run start` (which would boot the Hono
  server and fail without DATABASE_URL/GIT_REPOS_PATH secrets).
  Ships sensible security headers (nosniff, referrer-policy,
  X-Frame-Options).

No changes to src/, Dockerfile, fly.toml, package.json, or the
.github/workflows/fly-deploy.yml workflow. The Fly.io deploy path
remains the canonical production host for the real app; Vercel is
strictly a marketing surface until onboarding onto Crontech.

Routes that need the full app (/register, /explore, /api/*) are
linked out of the splash intentionally — they 404 on Vercel, which
is correct: the splash's only call-to-action is "see source on
GitHub / star" until the full app is live.

https://claude.ai/code/session_01AsMR7hPtK2KPBNEzrakmp4
Claude committed on April 22, 2026Parent: 9d3a6bb
2 files changed+432010d172b55a6e8db6f39ac26f35e115b3064a73c1
2 changed files+432−0
Addedpublic/index.html+413−0View fileUnifiedSplit
1<!doctype html>
2<html lang="en" data-theme="dark">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width,initial-scale=1" />
6 <title>gluecron — git hosting + AI review + CI in one binary</title>
7 <meta
8 name="description"
9 content="Self-hostable code platform with AI review, dependency updates, semantic search, and a workflow runner built in. No plugins. No bolt-ons. One binary."
10 />
11 <meta name="theme-color" content="#0d1117" />
12 <meta property="og:title" content="gluecron" />
13 <meta
14 property="og:description"
15 content="GitHub, but the AI actually ships the code."
16 />
17 <meta property="og:type" content="website" />
18 <link rel="canonical" href="https://gluecron.com/" />
19 <style>
20 :root {
21 --bg: #0d1117;
22 --bg-secondary: #161b22;
23 --bg-tertiary: #21262d;
24 --border: #30363d;
25 --text: #e6edf3;
26 --text-muted: #8b949e;
27 --text-link: #58a6ff;
28 --accent: #1f6feb;
29 --accent-hover: #388bfd;
30 --green: #3fb950;
31 --radius: 6px;
32 --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
33 --font-mono: 'SF Mono', 'Cascadia Code', 'Fira Code', ui-monospace, monospace;
34 }
35 * { box-sizing: border-box; }
36 html, body { margin: 0; padding: 0; }
37 body {
38 background: var(--bg);
39 color: var(--text);
40 font-family: var(--font-sans);
41 font-size: 15px;
42 line-height: 1.5;
43 -webkit-font-smoothing: antialiased;
44 }
45 a { color: var(--text-link); text-decoration: none; }
46 a:hover { text-decoration: underline; }
47 code {
48 font-family: var(--font-mono);
49 background: var(--bg-secondary);
50 border: 1px solid var(--border);
51 border-radius: 4px;
52 padding: 1px 6px;
53 font-size: 0.9em;
54 }
55 .btn {
56 display: inline-block;
57 padding: 10px 20px;
58 font-size: 15px;
59 font-weight: 600;
60 border-radius: var(--radius);
61 border: 1px solid var(--border);
62 cursor: pointer;
63 text-decoration: none;
64 transition: background 0.1s, border-color 0.1s;
65 }
66 .btn:hover { text-decoration: none; }
67 .btn-primary {
68 background: var(--accent);
69 border-color: var(--accent);
70 color: white;
71 }
72 .btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
73 .btn-secondary { background: transparent; color: var(--text); }
74 .btn-secondary:hover { background: var(--bg-secondary); }
75
76 .nav {
77 max-width: 1080px;
78 margin: 0 auto;
79 padding: 18px 16px;
80 display: flex;
81 align-items: center;
82 justify-content: space-between;
83 }
84 .nav-brand {
85 font-weight: 700;
86 color: var(--text);
87 font-size: 18px;
88 letter-spacing: -0.01em;
89 }
90 .nav-links { display: flex; gap: 22px; }
91 .nav-links a { color: var(--text-muted); font-size: 14px; }
92 .nav-links a:hover { color: var(--text); text-decoration: none; }
93
94 .hero {
95 padding: 72px 16px 56px;
96 text-align: center;
97 max-width: 860px;
98 margin: 0 auto;
99 border-bottom: 1px solid var(--border);
100 }
101 .hero h1 {
102 font-size: 44px;
103 line-height: 1.1;
104 letter-spacing: -0.02em;
105 margin: 0 0 20px;
106 font-weight: 700;
107 }
108 .hero p.sub {
109 font-size: 18px;
110 color: var(--text-muted);
111 margin: 0 auto 32px;
112 max-width: 640px;
113 }
114 .hero-ctas {
115 display: flex;
116 gap: 12px;
117 justify-content: center;
118 flex-wrap: wrap;
119 margin-bottom: 16px;
120 }
121 .trust {
122 font-size: 13px;
123 color: var(--text-muted);
124 margin-top: 12px;
125 letter-spacing: 0.02em;
126 }
127
128 .section {
129 padding: 64px 16px;
130 max-width: 1080px;
131 margin: 0 auto;
132 border-bottom: 1px solid var(--border);
133 }
134 .section h2 {
135 font-size: 28px;
136 font-weight: 700;
137 margin: 0 0 12px;
138 letter-spacing: -0.01em;
139 }
140 .section p.sub {
141 font-size: 15px;
142 color: var(--text-muted);
143 margin: 0 0 36px;
144 max-width: 680px;
145 line-height: 1.6;
146 }
147
148 .grid {
149 display: grid;
150 grid-template-columns: repeat(3, 1fr);
151 gap: 16px;
152 }
153 @media (max-width: 880px) { .grid { grid-template-columns: repeat(2, 1fr); } }
154 @media (max-width: 560px) { .grid { grid-template-columns: 1fr; } }
155
156 .feature {
157 background: var(--bg-secondary);
158 border: 1px solid var(--border);
159 border-radius: var(--radius);
160 padding: 22px;
161 }
162 .feature-icon {
163 font-size: 24px;
164 margin-bottom: 10px;
165 line-height: 1;
166 }
167 .feature h3 {
168 font-size: 16px;
169 font-weight: 600;
170 margin: 0 0 8px;
171 color: var(--text);
172 }
173 .feature p {
174 font-size: 14px;
175 color: var(--text-muted);
176 margin: 0;
177 line-height: 1.5;
178 }
179
180 .compare-grid {
181 display: grid;
182 grid-template-columns: 1fr 1fr;
183 gap: 16px;
184 }
185 @media (max-width: 680px) { .compare-grid { grid-template-columns: 1fr; } }
186 .compare-col {
187 background: var(--bg-secondary);
188 border: 1px solid var(--border);
189 border-radius: var(--radius);
190 padding: 24px;
191 }
192 .compare-col h3 {
193 font-size: 18px;
194 margin: 0 0 16px;
195 font-weight: 600;
196 }
197 .compare-col ul {
198 list-style: none;
199 padding: 0;
200 margin: 0;
201 }
202 .compare-col li {
203 padding: 6px 0;
204 font-size: 14px;
205 color: var(--text);
206 }
207 .compare-us { border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); }
208 .check { color: var(--green); font-weight: 700; margin-right: 8px; }
209 .dash { color: var(--text-muted); margin-right: 8px; }
210
211 .steps {
212 display: grid;
213 grid-template-columns: repeat(3, 1fr);
214 gap: 20px;
215 }
216 @media (max-width: 720px) { .steps { grid-template-columns: 1fr; } }
217 .step {
218 background: var(--bg-secondary);
219 border: 1px solid var(--border);
220 border-radius: var(--radius);
221 padding: 24px;
222 }
223 .step-num {
224 display: inline-flex;
225 align-items: center;
226 justify-content: center;
227 width: 32px;
228 height: 32px;
229 border-radius: 16px;
230 background: var(--accent);
231 color: white;
232 font-weight: 700;
233 margin-bottom: 14px;
234 }
235 .step h3 { margin: 0 0 8px; font-size: 16px; font-weight: 600; }
236 .step p { margin: 0; color: var(--text-muted); font-size: 14px; }
237
238 .cta-band {
239 text-align: center;
240 padding: 72px 16px;
241 max-width: 860px;
242 margin: 0 auto;
243 border-bottom: 1px solid var(--border);
244 }
245 .cta-band h2 { font-size: 32px; margin: 0 0 14px; font-weight: 700; }
246 .cta-band p { color: var(--text-muted); margin: 0 0 28px; font-size: 16px; }
247
248 footer {
249 max-width: 1080px;
250 margin: 0 auto;
251 padding: 36px 16px 72px;
252 text-align: center;
253 font-size: 13px;
254 color: var(--text-muted);
255 }
256 footer a { color: var(--text-muted); margin: 0 10px; }
257 footer a:hover { color: var(--text); }
258 </style>
259 </head>
260 <body>
261 <nav class="nav">
262 <a href="/" class="nav-brand">gluecron</a>
263 <div class="nav-links">
264 <a href="#features">Features</a>
265 <a href="#compare">vs GitHub</a>
266 <a href="#how">How it works</a>
267 </div>
268 </nav>
269
270 <section class="hero">
271 <h1>GitHub, but the AI actually ships the code.</h1>
272 <p class="sub">
273 gluecron is a self-hostable code platform with AI review, dependency
274 updates, semantic search, and a workflow runner built in. No plugins.
275 No bolt-ons. One binary.
276 </p>
277 <div class="hero-ctas">
278 <a href="#how" class="btn btn-primary">See how it works</a>
279 <a href="https://github.com/ccantynz-alt/Gluecron.com" class="btn btn-secondary">Source on GitHub</a>
280 </div>
281 <p class="trust">Self-hostable · AI built in · Open source mindset</p>
282 </section>
283
284 <section id="features" class="section">
285 <h2>Everything in one binary</h2>
286 <p class="sub">
287 The features GitHub sells as separate products (Dependabot, Copilot,
288 Actions, Advanced Security) ship with gluecron by default.
289 </p>
290 <div class="grid">
291 <div class="feature">
292 <div class="feature-icon" aria-hidden="true"></div>
293 <h3>AI code review</h3>
294 <p>Claude Sonnet reviews every PR with inline comments. Can block merges when configured in branch protection.</p>
295 </div>
296 <div class="feature">
297 <div class="feature-icon" aria-hidden="true"></div>
298 <h3>AI dependency updates</h3>
299 <p>Scans <code>package.json</code>, opens PRs with bump tables, writes the branch via git plumbing. Dependabot without the setup.</p>
300 </div>
301 <div class="feature">
302 <div class="feature-icon" aria-hidden="true"></div>
303 <h3>Semantic code search</h3>
304 <p>voyage-code-3 embeddings over every chunk, with lexical fallback. Finds code by intent, not just text.</p>
305 </div>
306 <div class="feature">
307 <div class="feature-icon" aria-hidden="true">📖</div>
308 <h3>Explain this codebase</h3>
309 <p>One click gets you a per-commit cached Markdown tour of the repo. Onboarding that writes itself.</p>
310 </div>
311 <div class="feature">
312 <div class="feature-icon" aria-hidden="true"></div>
313 <h3>Signed commit verification</h3>
314 <p>GPG and SSH signatures, Issuer Fingerprint extraction, a green Verified badge on the commit list.</p>
315 </div>
316 <div class="feature">
317 <div class="feature-icon" aria-hidden="true"></div>
318 <h3>Merge queues + required checks</h3>
319 <p>Serialised merges with re-test against the latest base. Per-branch required check matrix, enforced at merge.</p>
320 </div>
321 <div class="feature">
322 <div class="feature-icon" aria-hidden="true"></div>
323 <h3>Self-hosted workflow runner</h3>
324 <p>Actions-equivalent runner reads <code>.gluecron/workflows/*.yml</code>. Bun subprocesses, size-capped logs, per-step timeouts.</p>
325 </div>
326 <div class="feature">
327 <div class="feature-icon" aria-hidden="true">📦</div>
328 <h3>npm-protocol package registry</h3>
329 <p>Publish, install, yank over the real npm protocol. PAT-auth via <code>.npmrc</code>. No separate service to run.</p>
330 </div>
331 <div class="feature">
332 <div class="feature-icon" aria-hidden="true">🔐</div>
333 <h3>Enterprise SSO (OIDC)</h3>
334 <p>Okta, Azure AD, Auth0, Google Workspace. Auth-code flow, state+nonce, optional email-domain allow-list.</p>
335 </div>
336 </div>
337 </section>
338
339 <section id="compare" class="section">
340 <h2>gluecron vs GitHub</h2>
341 <p class="sub">
342 Honest comparison. GitHub is excellent at what it does. gluecron is
343 built for teams that want AI and CI in one place, on infrastructure
344 they control.
345 </p>
346 <div class="compare-grid">
347 <div class="compare-col compare-us">
348 <h3>gluecron</h3>
349 <ul>
350 <li><span class="check"></span>Self-host on your own box</li>
351 <li><span class="check"></span>AI review and completion included</li>
352 <li><span class="check"></span>Dependency updater included</li>
353 <li><span class="check"></span>Workflow runner included</li>
354 <li><span class="check"></span>Semantic search included</li>
355 <li><span class="check"></span>Green-by-default (gates, protection, codeowners)</li>
356 <li><span class="check"></span>One binary. One database. One deploy.</li>
357 </ul>
358 </div>
359 <div class="compare-col">
360 <h3>GitHub</h3>
361 <ul>
362 <li><span class="dash"></span>SaaS-first (Enterprise Server is separate)</li>
363 <li><span class="dash"></span>Copilot billed per seat</li>
364 <li><span class="dash"></span>Dependabot configured per repo</li>
365 <li><span class="dash"></span>Actions minutes metered</li>
366 <li><span class="dash"></span>Code search is lexical by default</li>
367 <li><span class="dash"></span>Advanced Security is an add-on</li>
368 <li><span class="dash"></span>Many moving pieces to wire together</li>
369 </ul>
370 </div>
371 </div>
372 </section>
373
374 <section id="how" class="section">
375 <h2>How it works</h2>
376 <div class="steps">
377 <div class="step">
378 <div class="step-num">1</div>
379 <h3>Push code</h3>
380 <p><code>git push</code> to gluecron. Standard Smart HTTP. No agent to install.</p>
381 </div>
382 <div class="step">
383 <div class="step-num">2</div>
384 <h3>Gates + AI review run</h3>
385 <p>Secret scanner, security gate, AI reviewer, and your workflows fire automatically. Rulesets enforce push policy.</p>
386 </div>
387 <div class="step">
388 <div class="step-num">3</div>
389 <h3>Green pushes auto-deploy</h3>
390 <p>Default-branch commits that pass all gates trigger your configured deploy webhook. Failed deploys open an AI-authored incident issue.</p>
391 </div>
392 </div>
393 </section>
394
395 <section class="cta-band">
396 <h2>Ready to push?</h2>
397 <p>The full platform goes live on the production host shortly. Star the repo to be notified.</p>
398 <div class="hero-ctas">
399 <a href="https://github.com/ccantynz-alt/Gluecron.com" class="btn btn-primary">Star on GitHub</a>
400 </div>
401 </section>
402
403 <footer>
404 <a href="https://github.com/ccantynz-alt/Gluecron.com">Source</a>
405 <span>·</span>
406 <a href="https://github.com/ccantynz-alt/Gluecron.com/blob/main/legal/TERMS.md">Terms</a>
407 <span>·</span>
408 <a href="https://github.com/ccantynz-alt/Gluecron.com/blob/main/legal/PRIVACY.md">Privacy</a>
409 <span>·</span>
410 <a href="https://github.com/ccantynz-alt/Gluecron.com/blob/main/legal/AUP.md">Acceptable Use</a>
411 </footer>
412 </body>
413</html>
Addedvercel.json+19−0View fileUnifiedSplit
1{
2 "$schema": "https://openapi.vercel.sh/vercel.json",
3 "framework": null,
4 "buildCommand": null,
5 "installCommand": null,
6 "outputDirectory": "public",
7 "cleanUrls": true,
8 "trailingSlash": false,
9 "headers": [
10 {
11 "source": "/(.*)",
12 "headers": [
13 { "key": "X-Content-Type-Options", "value": "nosniff" },
14 { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
15 { "key": "X-Frame-Options", "value": "DENY" }
16 ]
17 }
18 ]
19}
020