Repository navigation
Expand file tree
/
Copy pathvision.html
More file actions
647 lines (625 loc) · 34.5 KB
/
Copy pathvision.html
File metadata and controls
647 lines (625 loc) · 34.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
---
layout: null
title: Vision
permalink: /vision/
nav_order: 8
nav_exclude: true
search_exclude: true
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Provasign product strategy</title>
<meta http-equiv="refresh" content="0; url={{ '/' | relative_url }}">
<meta name="robots" content="noindex">
<meta name="description" content="This page has moved to the Provasign product overview for Prism, Shale, and Mason.">
<link rel="canonical" href="{{ '/' | absolute_url }}">
<meta property="og:site_name" content="Provasign">
<meta property="og:title" content="Provasign — every AI-written change should explain itself">
<meta property="og:description" content="Prism provides change intelligence. Shale carries evidence into review. Mason is the reference agent built on both.">
<meta property="og:url" content="{{ '/' | absolute_url }}">
<meta property="og:type" content="website">
<meta property="og:image" content="{{ '/assets/images/og-image.png' | absolute_url }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="{{ '/assets/images/og-image.png' | absolute_url }}">
<link rel="icon" type="image/svg+xml" href="{{ '/assets/images/logo-icon.svg' | relative_url }}">
<style>
:root {
--bg: #0d1117;
--panel: #161b22;
--panel2: #101820;
--text: #e6edf3;
--muted: #9aa7b4;
--dim: #748190;
--line: #273241;
--accent: #38d996;
--accent2: #7dd3fc;
--warn: #fbbf24;
--violet: #c084fc;
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--sans); overflow-x: hidden; }
a { color: inherit; }
.nav {
position: sticky; top: 0; z-index: 10;
display: flex; justify-content: space-between; align-items: center;
height: 60px; padding: 0 32px; background: rgba(13,17,23,.92);
border-bottom: 1px solid var(--line); backdrop-filter: blur(12px);
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 750; text-decoration: none; }
.brand svg { width: 26px; height: 26px; display: block; }
.navlinks { display: flex; align-items: center; gap: 18px; font-size: 14px; color: var(--muted); }
.navlinks a { text-decoration: none; }
.navlinks a:hover { color: var(--accent); }
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 28px; }
/* ---------- hero ---------- */
.hero { position: relative; padding: 110px 0 96px; border-bottom: 1px solid var(--line); overflow: hidden; }
.constellation {
position: absolute; inset: 0; width: 100%; height: 100%;
opacity: .5; pointer-events: none;
}
.constellation line { stroke: var(--line); stroke-width: 1; }
.constellation circle { fill: var(--accent); }
.constellation circle.c2 { fill: var(--accent2); }
.constellation circle.c3 { fill: var(--dim); }
.constellation circle { animation: nodepulse 4.5s ease-in-out infinite; transform-origin: center; transform-box: fill-box; }
.constellation circle:nth-of-type(2n) { animation-delay: -1.3s; }
.constellation circle:nth-of-type(3n) { animation-delay: -2.6s; }
.constellation circle:nth-of-type(5n) { animation-delay: -3.7s; animation-duration: 6s; }
@keyframes nodepulse {
0%, 100% { opacity: .35; transform: scale(1); }
50% { opacity: 1; transform: scale(1.6); }
}
.hero .wrap { position: relative; }
.eyebrow { color: var(--accent); font-family: var(--mono); font-size: 13px; margin-bottom: 18px; letter-spacing: .04em; }
h1 {
max-width: 980px; margin: 0;
font-size: clamp(44px, 7.4vw, 86px); line-height: .98; letter-spacing: -.04em;
}
h1 .shimmer {
background: linear-gradient(100deg, var(--accent) 20%, var(--accent2) 45%, var(--accent) 70%);
background-size: 220% 100%;
-webkit-background-clip: text; background-clip: text;
-webkit-text-fill-color: transparent; color: transparent;
animation: shimmer 5.5s linear infinite;
}
@keyframes shimmer { to { background-position: -220% 0; } }
.lead { max-width: 740px; margin: 30px 0 0; color: var(--muted); font-size: 21px; line-height: 1.6; }
.lead strong { color: var(--text); }
.cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }
.btn {
display: inline-flex; align-items: center; justify-content: center;
min-height: 42px; padding: 0 18px; border-radius: 7px; text-decoration: none;
font-weight: 700; font-size: 15px; border: 1px solid var(--line);
}
.btn.primary { background: var(--accent); color: #042014; border-color: var(--accent); }
.btn.secondary { color: var(--text); }
/* ---------- sections / reveal ---------- */
.section { padding: 84px 0 64px; border-top: 1px solid var(--line); }
.section h2 { margin: 0 0 16px; font-size: clamp(30px, 4vw, 40px); letter-spacing: -.03em; }
.section > .wrap > p, .prose p { max-width: 760px; color: var(--muted); line-height: 1.75; font-size: 17.5px; }
.prose strong, .section p strong { color: var(--text); }
.kicker { color: var(--accent); font-family: var(--mono); font-size: 13px; margin-bottom: 14px; letter-spacing: .04em; }
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .8s ease, transform .8s ease; }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .12s; }
.reveal.d2 { transition-delay: .24s; }
.reveal.d3 { transition-delay: .36s; }
/* ---------- act layout ---------- */
.act { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center; }
.act.flip .viz { order: -1; }
.act h3 { margin: 0 0 12px; font-size: 30px; letter-spacing: -.025em; }
.act h3 .toolname { color: var(--accent); }
.act p { color: var(--muted); line-height: 1.75; font-size: 17px; margin: 0 0 14px; }
.act .quote { border-left: 3px solid var(--accent); padding: 4px 0 4px 16px; color: var(--text); font-size: 17px; font-style: italic; }
.actnum { font-family: var(--mono); color: var(--dim); font-size: 13px; margin-bottom: 10px; }
.viz {
background: var(--panel2); border: 1px solid var(--line); border-radius: 12px;
padding: 18px; overflow: hidden;
}
.viz svg { width: 100%; height: auto; display: block; }
.vizlabel { font-family: var(--mono); font-size: 12px; fill: var(--muted); }
.vizlabel.bright { fill: var(--text); }
.vizlabel.dimmer { fill: var(--dim); }
/* prism refraction */
.beam-in { stroke: #e6edf3; stroke-width: 2.5; stroke-dasharray: 230; stroke-dashoffset: 230; }
.in .beam-in { animation: draw 1.1s ease forwards; }
.beam-out { stroke-width: 2.5; stroke-dasharray: 300; stroke-dashoffset: 300; opacity: .95; }
.in .beam-out { animation: draw 1.2s ease forwards; }
.in .beam-out.b1 { animation-delay: .9s; }
.in .beam-out.b2 { animation-delay: 1.05s; }
.in .beam-out.b3 { animation-delay: 1.2s; }
.in .beam-out.b4 { animation-delay: 1.35s; }
.prism-body { fill: rgba(125,211,252,.07); stroke: var(--accent2); stroke-width: 1.6; }
.prism-glow { opacity: 0; }
.in .prism-glow { animation: glowin 1.4s ease .8s forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes glowin { to { opacity: 1; } }
.bandlabel { opacity: 0; }
.in .bandlabel { animation: glowin .7s ease forwards; }
.in .bandlabel.b1 { animation-delay: 1.5s; }
.in .bandlabel.b2 { animation-delay: 1.65s; }
.in .bandlabel.b3 { animation-delay: 1.8s; }
.in .bandlabel.b4 { animation-delay: 1.95s; }
/* fuse merge */
.branch { fill: none; stroke-width: 2.5; stroke-dasharray: 420; stroke-dashoffset: 420; }
.in .branch { animation: draw 1.6s ease forwards; }
.in .branch.b { animation-delay: .25s; }
.merged { fill: none; stroke: var(--accent); stroke-width: 3; stroke-dasharray: 300; stroke-dashoffset: 300; }
.in .merged { animation: draw 1.1s ease 1.5s forwards; }
.fusespark { opacity: 0; }
.in .fusespark { animation: spark 2.2s ease 1.4s infinite; }
@keyframes spark {
0% { opacity: 0; r: 5; }
15% { opacity: 1; }
45% { opacity: .25; r: 13; }
100% { opacity: 0; r: 5; }
}
.commit-dot { opacity: 0; }
.in .commit-dot { animation: glowin .5s ease forwards; }
.in .commit-dot.c1 { animation-delay: .5s; }
.in .commit-dot.c2 { animation-delay: .8s; }
.in .commit-dot.c3 { animation-delay: 1.1s; }
.in .commit-dot.c4 { animation-delay: 2.2s; }
.in .commit-dot.c5 { animation-delay: 2.45s; }
/* shale strata */
.stratum { opacity: 0; transform: translateY(18px); transform-box: fill-box; }
.in .stratum { animation: settle .8s cubic-bezier(.2,.7,.3,1) forwards; }
.in .stratum.s1 { animation-delay: .15s; }
.in .stratum.s2 { animation-delay: .45s; }
.in .stratum.s3 { animation-delay: .75s; }
.in .stratum.s4 { animation-delay: 1.05s; }
.in .stratum.s5 { animation-delay: 1.35s; }
@keyframes settle { to { opacity: 1; transform: translateY(0); } }
/* loop diagram */
.loopwrap { margin-top: 44px; background: var(--panel2); border: 1px solid var(--line); border-radius: 12px; padding: 26px 18px 10px; }
.loopwrap svg { width: 100%; height: auto; display: block; }
.loopnode { fill: var(--panel); stroke: var(--line); stroke-width: 1.4; }
.loopnode.groot { stroke: var(--accent); }
.loopedge { stroke: var(--line); stroke-width: 1.6; fill: none; }
.looproot { stroke: rgba(56,217,150,.55); stroke-width: 1.4; stroke-dasharray: 4 5; fill: none; }
.looptitle { font: 700 16px var(--sans); fill: var(--text); }
.loopsub { font: 12px var(--mono); fill: var(--accent); }
.loopsub.cyan { fill: var(--accent2); }
.pulse-dot { fill: var(--accent); }
.pulse-dot2 { fill: var(--accent2); }
/* roadmap */
.timeline { position: relative; margin-top: 46px; padding-left: 34px; max-width: 800px; }
.timeline::before {
content: ""; position: absolute; left: 9px; top: 6px; bottom: 6px; width: 2px;
background: linear-gradient(180deg, var(--accent), var(--accent2), var(--violet));
border-radius: 2px;
}
.stop { position: relative; padding: 0 0 44px; }
.stop:last-child { padding-bottom: 6px; }
.stop::before {
content: ""; position: absolute; left: -32px; top: 6px; width: 14px; height: 14px;
border-radius: 50%; background: var(--bg); border: 3px solid var(--accent);
}
.stop.next::before { border-color: var(--accent2); }
.stop.dream::before { border-color: var(--violet); box-shadow: 0 0 14px rgba(192,132,252,.55); }
.stop .when { font-family: var(--mono); font-size: 13px; color: var(--accent); margin-bottom: 8px; }
.stop.next .when { color: var(--accent2); }
.stop.dream .when { color: var(--violet); }
.stop h3 { margin: 0 0 10px; font-size: 23px; letter-spacing: -.02em; }
.stop p { margin: 0; color: var(--muted); line-height: 1.7; font-size: 16.5px; max-width: 720px; }
.stop a { color: var(--accent2); }
.stop ul { margin: 10px 0 0; padding-left: 20px; color: var(--muted); line-height: 1.7; font-size: 16.5px; }
/* principles */
.bullets { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 30px; }
.bullet { padding: 18px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel2); color: var(--muted); line-height: 1.55; }
.bullet strong { color: var(--text); }
/* closing */
.closing { text-align: center; padding: 100px 0 110px; }
.closing h2 { font-size: clamp(32px, 5vw, 54px); letter-spacing: -.035em; margin: 0 0 18px; }
.closing p { color: var(--muted); font-size: 19px; max-width: 640px; margin: 0 auto 34px; line-height: 1.65; }
.closing .cta { justify-content: center; }
footer { border-top: 1px solid var(--line); padding: 28px 0; color: var(--dim); font-size: 14px; }
@media (max-width: 920px) {
.act { grid-template-columns: 1fr; gap: 26px; }
.act.flip .viz { order: 0; }
.bullets { grid-template-columns: 1fr; }
}
@media (max-width: 800px) {
.nav { padding: 0 18px; }
.navlinks { gap: 10px; font-size: 13px; }
.hero { padding-top: 70px; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.reveal { opacity: 1; transform: none; transition: none; }
.constellation circle, h1 .shimmer { animation: none; }
.beam-in, .beam-out, .branch, .merged { stroke-dashoffset: 0; animation: none !important; }
.prism-glow, .bandlabel, .commit-dot { opacity: 1; animation: none !important; }
.stratum { opacity: 1; transform: none; animation: none !important; }
.fusespark { animation: none !important; opacity: .6; }
}
</style>
</head>
<body>
<nav class="nav">
<a class="brand" href="{{ '/' | relative_url }}"><svg viewBox="0 0 64 64" aria-hidden="true"><rect x="6" y="8" width="40" height="9" rx="3" fill="#38d996"/><rect x="18" y="21" width="40" height="9" rx="3" fill="#94a3b8"/><rect x="6" y="34" width="40" height="9" rx="3" fill="#64748b"/><rect x="18" y="47" width="40" height="9" rx="3" fill="#475569"/></svg> Shale</a>
<div class="navlinks">
<a href="{{ '/vision/' | relative_url }}">Vision</a>
<a href="{{ '/docs/' | relative_url }}">Docs</a>
<a href="{{ '/shale/' | relative_url }}">Shale</a>
<a href="{{ '/prism/' | relative_url }}">Prism</a>
<a href="{{ '/fuse/' | relative_url }}">Fuse</a>
<a href="{{ '/grove/' | relative_url }}">Grove</a>
<a href="https://github.com/provasign/shale">GitHub</a>
</div>
</nav>
<main>
<!-- ================= HERO ================= -->
<section class="hero">
<svg class="constellation" viewBox="0 0 1200 560" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<line x1="120" y1="90" x2="300" y2="160"/><line x1="300" y1="160" x2="480" y2="80"/>
<line x1="300" y1="160" x2="380" y2="330"/><line x1="480" y1="80" x2="700" y2="140"/>
<line x1="700" y1="140" x2="880" y2="70"/><line x1="700" y1="140" x2="760" y2="300"/>
<line x1="880" y1="70" x2="1080" y2="150"/><line x1="760" y1="300" x2="1080" y2="150"/>
<line x1="380" y1="330" x2="600" y2="420"/><line x1="600" y1="420" x2="760" y2="300"/>
<line x1="120" y1="90" x2="60" y2="280"/><line x1="60" y1="280" x2="380" y2="330"/>
<line x1="600" y1="420" x2="520" y2="520"/><line x1="1080" y1="150" x2="1150" y2="340"/>
<line x1="760" y1="300" x2="940" y2="430"/><line x1="940" y1="430" x2="1150" y2="340"/>
<circle cx="120" cy="90" r="4"/><circle cx="300" cy="160" r="5" class="c2"/>
<circle cx="480" cy="80" r="3.5" class="c3"/><circle cx="700" cy="140" r="5"/>
<circle cx="880" cy="70" r="3.5" class="c2"/><circle cx="1080" cy="150" r="4.5"/>
<circle cx="380" cy="330" r="4" class="c2"/><circle cx="760" cy="300" r="5.5"/>
<circle cx="600" cy="420" r="4" class="c3"/><circle cx="60" cy="280" r="3.5"/>
<circle cx="520" cy="520" r="3.5" class="c2"/><circle cx="1150" cy="340" r="4" class="c3"/>
<circle cx="940" cy="430" r="4.5"/>
</svg>
<div class="wrap">
<div class="eyebrow">THE PROVASIGN VISION</div>
<h1>Agents write the code.<br><span class="shimmer">The graph keeps the truth.</span></h1>
<p class="lead">
AI agents now produce a huge share of the world's new code — and every hour
saved writing it is being spent wondering whether to trust it.
We're building the missing layer: <strong>one local code graph that helps an
agent write, merges what it wrote, and proves what it did</strong> — on the
pull request, where trust is actually decided.
</p>
<div class="cta">
<a class="btn primary" href="#the-loop">See the loop</a>
<a class="btn secondary" href="{{ '/' | relative_url }}">Meet the tools</a>
</div>
</div>
</section>
<!-- ================= THE SHIFT ================= -->
<section class="section">
<div class="wrap prose">
<div class="reveal">
<div class="kicker">// THE SHIFT</div>
<h2>The bottleneck moved.</h2>
<p>
For seventy years the scarce resource in software was <em>writing it</em>.
That era just ended. An agent drafts in minutes what a team used to ship in
a sprint — and the cost didn't disappear, it moved downstream. Now the
questions pile up at review time: <strong>What did it actually change?
What does that change touch? Did anything test it? Why is there a CI file
in this diff?</strong>
</p>
<p>
The industry's answer so far has been to point a second model at the
output of the first and ask it to vibe-check the work. We think reviewers
deserve better than vibes.
</p>
</div>
<div class="reveal d1">
<p>
Your codebase already contains the truth. Every function knows its
callers. Every test knows what it exercises. Every change has a blast
radius that is a <em>fact of structure</em>, not a matter of opinion.
<strong>Grove</strong> turns that structure into a persistent, local
graph — and everything we build follows from one idea:
</p>
<p style="font-size: 22px; color: var(--text); border-left: 3px solid var(--accent); padding: 6px 0 6px 20px; max-width: 720px;">
If the graph is good enough to help an agent <em>write</em> code,
it's good enough to <em>merge</em> that code — and to
<em>explain it</em> to the human who has to say yes.
</p>
</div>
</div>
</section>
<!-- ================= ACT I — PRISM ================= -->
<section class="section">
<div class="wrap">
<div class="act reveal">
<div>
<div class="actnum">ACT I — WHILE THE CODE IS WRITTEN</div>
<h3><span class="toolname">Prism</span> · write with context</h3>
<p>
A task hits a codebase the way white light hits glass. Prism refracts
it: definitions, callers, structurally related tests, coverage gaps —
ranked by the graph, budgeted in tokens, delivered before the agent
writes a line.
</p>
<p>
The agent stops grepping and starts <em>knowing</em>. Better context in;
fewer hallucinated edits out; and a session that costs less because the
graph did the searching.
</p>
<p class="quote">Every token spent re-discovering the codebase is a token
not spent on the change.</p>
</div>
<div class="viz">
<svg viewBox="0 0 560 300" role="img" aria-label="A white beam labeled 'your task' enters a prism and splits into four labeled bands: definitions, callers, tests, coverage gaps">
<line class="beam-in" x1="10" y1="150" x2="232" y2="150"/>
<text class="vizlabel bright" x="14" y="136">your task</text>
<polygon class="prism-body" points="226,214 296,214 261,86"/>
<g class="prism-glow">
<circle cx="261" cy="172" r="26" fill="rgba(125,211,252,.12)"/>
<circle cx="261" cy="172" r="12" fill="rgba(125,211,252,.22)"/>
</g>
<line class="beam-out b1" x1="288" y1="138" x2="544" y2="62" stroke="#7dd3fc"/>
<line class="beam-out b2" x1="292" y1="152" x2="544" y2="128" stroke="#38d996"/>
<line class="beam-out b3" x1="292" y1="166" x2="544" y2="194" stroke="#fbbf24"/>
<line class="beam-out b4" x1="288" y1="180" x2="544" y2="260" stroke="#c084fc"/>
<text class="bandlabel b1 vizlabel" x="430" y="52" fill="#7dd3fc">definitions</text>
<text class="bandlabel b2 vizlabel" x="446" y="118" fill="#38d996">callers</text>
<text class="bandlabel b3 vizlabel" x="454" y="216" fill="#fbbf24">tests</text>
<text class="bandlabel b4 vizlabel" x="408" y="282" fill="#c084fc">coverage gaps</text>
</svg>
</div>
</div>
</div>
</section>
<!-- ================= ACT II — FUSE ================= -->
<section class="section">
<div class="wrap">
<div class="act flip reveal">
<div class="viz">
<svg viewBox="0 0 560 220" role="img" aria-label="Two branch lines from agent A and agent B converge at a fuse point into one merged history">
<path class="branch" d="M14,58 C170,58 200,110 280,110" stroke="#7dd3fc"/>
<path class="branch b" d="M14,162 C170,162 200,110 280,110" stroke="#c084fc"/>
<path class="merged" d="M280,110 L546,110"/>
<circle class="commit-dot c1" cx="80" cy="60" r="5" fill="#7dd3fc"/>
<circle class="commit-dot c2" cx="158" cy="66" r="5" fill="#7dd3fc"/>
<circle class="commit-dot c1" cx="80" cy="160" r="5" fill="#c084fc"/>
<circle class="commit-dot c3" cx="158" cy="154" r="5" fill="#c084fc"/>
<circle class="fusespark" cx="280" cy="110" r="6" fill="#38d996"/>
<circle cx="280" cy="110" r="6" fill="#38d996"/>
<circle class="commit-dot c4" cx="400" cy="110" r="5" fill="#38d996"/>
<circle class="commit-dot c5" cx="480" cy="110" r="5" fill="#38d996"/>
<text class="vizlabel" x="16" y="40" fill="#7dd3fc">agent A</text>
<text class="vizlabel" x="16" y="192" fill="#c084fc">agent B</text>
<text class="vizlabel bright" x="452" y="92">one history</text>
<text class="vizlabel dimmer" x="222" y="146">symbol-aware</text>
</svg>
</div>
<div>
<div class="actnum">ACT II — WHEN THE WORK COMES TOGETHER</div>
<h3><span class="toolname">Fuse</span> · merge with confidence</h3>
<p>
Parallel agents collide where parallel humans always have: at merge
time. But agents collide more often, at higher speed, in the same
files. Line-based merging was never built for this.
</p>
<p>
Fuse merges at the <strong>symbol level</strong> — it resolves what is
structurally compatible and trips safely on what isn't, handing the
conflict to an agent with the full context of both sides. Like its
electrical namesake: when something's wrong, it breaks the circuit
before the circuit burns. Every merge leaves drift evidence behind.
</p>
<p class="quote">Two lines touching the same region isn't a conflict.
Two changes breaking the same contract is.</p>
</div>
</div>
</div>
</section>
<!-- ================= ACT III — SHALE ================= -->
<section class="section">
<div class="wrap">
<div class="act reveal">
<div>
<div class="actnum">ACT III — WHEN A HUMAN HAS TO DECIDE</div>
<h3><span class="toolname">Shale</span> · review with evidence</h3>
<p>
A session settles into strata: the intent that was declared, the files
that were touched, the checks that ran, the gaps that remain. Shale
compacts a messy agent session into thin, readable layers on the pull
request — <strong>evidence, not summary</strong>.
</p>
<p>
It is deliberately honest about uncertainty. It shows what it observed
and admits what it didn't, because a trust tool that overclaims is
worse than no tool at all. Advisory, never gatekeeping. No server, no
account, no transcript ever leaving the machine.
</p>
<p class="quote">Every AI-agent PR should explain itself.</p>
</div>
<div class="viz">
<svg viewBox="0 0 560 250" role="img" aria-label="Five sediment layers settle into place, labeled intent, changed files, checks run, blast radius, gaps admitted">
<g class="stratum s1">
<rect x="40" y="30" width="330" height="30" rx="6" fill="#38d996"/>
<text class="vizlabel bright" x="390" y="50">intent declared</text>
</g>
<g class="stratum s2">
<rect x="70" y="68" width="330" height="30" rx="6" fill="#7dd3fc" opacity=".85"/>
<text class="vizlabel bright" x="420" y="88">changed files</text>
</g>
<g class="stratum s3">
<rect x="40" y="106" width="330" height="30" rx="6" fill="#94a3b8" opacity=".8"/>
<text class="vizlabel bright" x="390" y="126">checks run</text>
</g>
<g class="stratum s4">
<rect x="70" y="144" width="330" height="30" rx="6" fill="#64748b" opacity=".85"/>
<text class="vizlabel bright" x="420" y="164">blast radius</text>
</g>
<g class="stratum s5">
<rect x="40" y="182" width="330" height="30" rx="6" fill="#fbbf24" opacity=".75"/>
<text class="vizlabel bright" x="390" y="202">gaps admitted</text>
</g>
<text class="vizlabel dimmer" x="40" y="238">a session, compacted into evidence</text>
</svg>
</div>
</div>
</div>
</section>
<!-- ================= THE LOOP ================= -->
<section class="section" id="the-loop">
<div class="wrap">
<div class="reveal">
<div class="kicker">// WHY THIS IS DIFFERENT</div>
<h2>One graph. The whole loop.</h2>
<p>
Plenty of tools do one of these things. Context retrieval is a feature.
Merge tooling is a feature. PR summaries are a feature.
<strong>The product is the loop</strong>: the same graph that delivers
context to the agent verifies the merge and renders the evidence —
so provenance survives from the first token the agent reads to the
moment a human clicks approve. And the entire loop runs on your
machine. No server. No account. No code leaving home.
</p>
</div>
<div class="loopwrap reveal d1">
<svg viewBox="0 0 760 320" role="img" aria-label="Write with Prism, merge with Fuse, review with Shale — all connected to one Grove graph underneath, with pulses traveling around the loop">
<path class="loopedge" d="M195,92 L325,92"/>
<path class="loopedge" d="M455,92 L585,92"/>
<path class="looproot" d="M130,118 C150,200 290,242 332,246"/>
<path class="looproot" d="M390,118 L390,238"/>
<path class="looproot" d="M650,118 C630,200 490,242 448,246"/>
<g>
<rect class="loopnode" x="65" y="56" width="130" height="62" rx="10"/>
<text class="looptitle" x="130" y="83" text-anchor="middle">Write</text>
<text class="loopsub" x="130" y="104" text-anchor="middle">prism</text>
</g>
<g>
<rect class="loopnode" x="325" y="56" width="130" height="62" rx="10"/>
<text class="looptitle" x="390" y="83" text-anchor="middle">Merge</text>
<text class="loopsub" x="390" y="104" text-anchor="middle">fuse</text>
</g>
<g>
<rect class="loopnode" x="585" y="56" width="130" height="62" rx="10"/>
<text class="looptitle" x="650" y="83" text-anchor="middle">Review</text>
<text class="loopsub" x="650" y="104" text-anchor="middle">shale</text>
</g>
<g>
<rect class="loopnode groot" x="320" y="238" width="140" height="58" rx="10"/>
<text class="looptitle" x="390" y="263" text-anchor="middle">One graph</text>
<text class="loopsub cyan" x="390" y="284" text-anchor="middle">grove</text>
</g>
<circle class="pulse-dot" r="4.5">
<animateMotion dur="6s" repeatCount="indefinite" begin="3s" path="M195,92 L325,92"/>
</circle>
<circle class="pulse-dot" r="4.5">
<animateMotion dur="6s" repeatCount="indefinite" begin="1.5s" path="M455,92 L585,92"/>
</circle>
<circle class="pulse-dot2" r="4">
<animateMotion dur="4s" repeatCount="indefinite" path="M332,246 C290,242 150,200 130,118"/>
</circle>
<circle class="pulse-dot2" r="4">
<animateMotion dur="4s" repeatCount="indefinite" begin="1.3s" path="M390,238 L390,118"/>
</circle>
<circle class="pulse-dot2" r="4">
<animateMotion dur="4s" repeatCount="indefinite" begin="2.6s" path="M448,246 C490,242 630,200 650,118"/>
</circle>
</svg>
</div>
<div class="bullets reveal d2">
<div class="bullet"><strong>Local-first is the architecture, not a tier.</strong> The graph lives in your repo. The evidence travels with your commits. There is no hosted dependency to outgrow or get acquired out from under you.</div>
<div class="bullet"><strong>Structure over scores.</strong> No magic 0–100 risk numbers. Facts a reviewer can check: callers, tests, sensitive paths, unexplained changes.</div>
<div class="bullet"><strong>Honest about uncertainty.</strong> "No structurally related tests found" — not "this change is untested." When the graph can't map something, it says so and fails open.</div>
<div class="bullet"><strong>Useful alone, compounding together.</strong> Adopt any one tool in five minutes. Each tool you add makes the others smarter, because they share the graph.</div>
</div>
</div>
</section>
<!-- ================= ROADMAP ================= -->
<section class="section">
<div class="wrap">
<div class="reveal">
<div class="kicker">// WHERE THIS GOES</div>
<h2>The road to the proof layer.</h2>
</div>
<div class="timeline">
<div class="stop reveal">
<div class="when">NOW — SHIPPED & STABLE</div>
<h3>The three moments, covered.</h3>
<p>
Prism delivers graph-ranked context. Fuse is a registered git merge
driver doing symbol-aware three-way merges. Shale renders intent,
evidence, checks, and gaps as a PR card. Grove holds the graph under
all of it. One brew tap, one <code style="font-family:var(--mono);font-size:14px;">init</code> per repo, Apache-2.0 everywhere.
</p>
</div>
<div class="stop next reveal d1">
<div class="when">NEXT — SEMANTIC REVIEW SIGNALS</div>
<h3>The PR card learns to read the graph.</h3>
<p>
Shale's card stops listing files and starts explaining structure
(<a href="https://github.com/provasign/shale/issues/5">RFC #5</a>):
</p>
<ul>
<li><strong>Changed symbols</strong>, not just changed files — and their blast radius in callers, handlers, and middleware.</li>
<li><strong>Structurally related tests</strong>, matched against the checks the agent actually ran locally.</li>
<li><strong>Out-of-neighborhood changes</strong> — the deploy workflow edited in an auth PR with no structural link to the rest of the diff — surfaced as review focus, not buried on page four.</li>
<li><strong>Risk badges grounded in facts</strong>: exported API changed, sensitive path, no related tests found, git-fallback evidence only.</li>
</ul>
</div>
<div class="stop dream reveal d2">
<div class="when">THE DREAM — EVIDENCE AS A FIRST-CLASS ARTIFACT</div>
<h3>Every change carries its own proof.</h3>
<p>
The end state we're building toward: a development loop where
provenance is continuous. The context an agent consumed (Prism), the
merges its work survived (Fuse), and the evidence of what it did
(Shale) chain together into a record that travels with the code —
reviewable by a human in thirty seconds, auditable by a machine
forever. Fleets of agents working in parallel on one repo, merging
without fear, opening PRs that argue their own case. The reviewer's
job stops being archaeology and becomes judgment.
</p>
<p style="margin-top: 12px;">
<em>Prova</em> + <em>sign</em>: agent work that can prove itself.
That's not a feature on a roadmap. It's the point.
</p>
</div>
</div>
</div>
</section>
<!-- ================= CLOSING ================= -->
<section class="section closing">
<div class="wrap reveal">
<h2>Written by agents.<br>Trusted by structure.<br><span style="color:var(--accent)">Proven on the PR.</span></h2>
<p>
All of it open source. All of it local-first. All of it five minutes
from <code style="font-family:var(--mono);font-size:15px;">brew tap provasign/tap</code> to your first evidence card.
</p>
<div class="cta">
<a class="btn primary" href="{{ '/' | relative_url }}">Get started</a>
<a class="btn secondary" href="https://github.com/provasign/shale/issues/5">Read the RFC</a>
<a class="btn secondary" href="https://github.com/provasign">GitHub</a>
</div>
</div>
</section>
</main>
<footer>
<div class="wrap">Shale, Prism, Fuse, and Grove · Open source, local-first tools for AI coding agents.</div>
</footer>
<script>
(function () {
var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var els = document.querySelectorAll('.reveal');
if (reduced || !('IntersectionObserver' in window)) {
els.forEach(function (el) { el.classList.add('in'); });
return;
}
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('in');
io.unobserve(entry.target);
}
});
}, { threshold: 0.22 });
els.forEach(function (el) { io.observe(el); });
})();
</script>
</body>
</html>