mirror of
https://github.com/jparkerweb/plan2code.git
synced 2026-09-17 16:22:23 -07:00
30860a7654
Adds a postage-stamp favicon set and banner, removes three orphaned images, and records the site and README as protected divergences so an upstream sync can't revert them. AI Assisted
390 lines
19 KiB
HTML
390 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Plan2Code — Spec-Driven Workflow for AI Coding Agents</title>
|
|
<meta name="description" content="Send the plan — the build follows. You approve a plan, it becomes phase documents in your repo, and the agent builds to those documents one phase at a time.">
|
|
<link rel="icon" href="favicon.ico" sizes="32x32">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon.png">
|
|
<link rel="icon" href="favicon.svg" type="image/svg+xml">
|
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@500;700;800&family=Karla:wght@300;400;500;600;700&family=Caveat:wght@500&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{
|
|
--air:#E4ECF6; --air-2:#D3DEEE; --paper:#FBFAF6;
|
|
--ink:#16233D; --ink-soft:#5E6E8A;
|
|
--red:#D33A38; --blue:#2455A4; --kraft:#E5D8BE;
|
|
}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{background:var(--air);color:var(--ink);font:400 16.5px/1.65 'Karla',system-ui,sans-serif;-webkit-font-smoothing:antialiased}
|
|
.bs{font-family:'Big Shoulders Display',sans-serif;font-weight:800;letter-spacing:.005em}
|
|
.hand{font-family:'Caveat',cursive}
|
|
.wrap{max-width:1140px;margin:0 auto;padding:0 34px}
|
|
a{color:inherit}
|
|
:focus-visible{outline:2px solid var(--red);outline-offset:3px}
|
|
|
|
/* ── SIGNATURE: airmail chevron border framing the page on all four sides ── */
|
|
:root{--fr:11px}
|
|
.frame-t,.frame-b,.frame-l,.frame-r{
|
|
position:fixed;z-index:60;pointer-events:none;
|
|
background:repeating-linear-gradient(-45deg,
|
|
var(--red) 0 14px, var(--paper) 14px 28px,
|
|
var(--blue) 28px 42px, var(--paper) 42px 56px);
|
|
}
|
|
.frame-t,.frame-b{left:0;right:0;height:var(--fr)}
|
|
.frame-t{top:0}
|
|
.frame-b{bottom:0}
|
|
.frame-l,.frame-r{top:0;bottom:0;width:var(--fr)}
|
|
.frame-l{left:0}
|
|
.frame-r{right:0}
|
|
body{padding:var(--fr)}
|
|
|
|
/* ── header (sticky, sits just under the top frame) ── */
|
|
.top{
|
|
background:var(--paper);border-bottom:2px solid var(--ink);
|
|
position:sticky;top:var(--fr);z-index:40;
|
|
}
|
|
.top .wrap{display:flex;align-items:center;gap:16px;padding-top:13px;padding-bottom:12px}
|
|
.brand{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:26px;letter-spacing:.01em;text-transform:uppercase}
|
|
.brand i{font-style:normal;color:var(--red)}
|
|
.avion{
|
|
margin-left:auto;border:1.5px solid var(--blue);color:var(--blue);
|
|
font-size:10px;letter-spacing:.22em;text-transform:uppercase;font-weight:700;padding:5px 11px;
|
|
}
|
|
|
|
/* ── hero: the envelope ── */
|
|
.hero{padding:56px 0 70px}
|
|
.env{
|
|
background:var(--paper);border:2px solid var(--ink);position:relative;
|
|
box-shadow:10px 12px 0 rgba(22,35,61,.14);padding:40px 42px 44px;
|
|
}
|
|
/* cancellation waves */
|
|
.cancel{position:absolute;right:34px;top:34px;width:210px;height:110px;pointer-events:none}
|
|
.cancel .ring{fill:none;stroke:var(--red);stroke-width:2.2}
|
|
.cancel .wv{fill:none;stroke:var(--red);stroke-width:2.2;opacity:.85}
|
|
.cancel text{font-family:'Karla',sans-serif;font-weight:700;fill:var(--red);letter-spacing:.06em}
|
|
/* stamp */
|
|
.pstamp{
|
|
position:absolute;right:250px;top:34px;width:86px;height:104px;background:var(--air-2);
|
|
border:2px solid var(--ink);padding:8px;text-align:center;
|
|
}
|
|
.pstamp .in{border:1px solid rgba(22,35,61,.35);height:100%;display:flex;flex-direction:column;justify-content:center;gap:2px}
|
|
.pstamp b{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:26px;line-height:1;color:var(--blue)}
|
|
.pstamp span{font-size:8px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);font-weight:700}
|
|
@media(max-width:900px){.cancel,.pstamp{display:none}}
|
|
|
|
.kick{font-size:10.5px;letter-spacing:.24em;text-transform:uppercase;color:var(--blue);font-weight:700}
|
|
h1{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(3rem,9vw,7rem);line-height:.86;text-transform:uppercase;margin-top:14px;max-width:13ch}
|
|
h1 em{font-style:normal;color:var(--red)}
|
|
.addr{
|
|
margin-top:32px;padding-top:26px;border-top:1.5px dashed rgba(22,35,61,.3);
|
|
display:grid;grid-template-columns:1fr 1fr;gap:36px;align-items:end;
|
|
}
|
|
.addr .to{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-soft);font-weight:700}
|
|
.addr p{margin-top:10px;color:var(--ink-soft);max-width:44ch}
|
|
.acts{display:flex;flex-wrap:wrap;gap:12px}
|
|
.btn{
|
|
display:inline-block;text-decoration:none;background:var(--ink);color:var(--paper);
|
|
font-family:'Big Shoulders Display',sans-serif;font-weight:700;font-size:19px;letter-spacing:.1em;
|
|
text-transform:uppercase;padding:12px 28px;transition:background .18s,transform .18s;
|
|
}
|
|
.btn:hover{background:var(--red);transform:translateY(-2px)}
|
|
.btn.-o{background:transparent;border:2px solid var(--ink);color:var(--ink);padding:10px 26px}
|
|
.btn.-o:hover{background:var(--ink);color:var(--paper)}
|
|
|
|
/* ── postage meter strip ── */
|
|
.meter{background:var(--ink);color:var(--paper)}
|
|
.meter .wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:0}
|
|
.meter div{padding:24px 18px;border-left:1px dashed rgba(251,250,246,.28)}
|
|
.meter div:first-child{border-left:none}
|
|
.meter b{display:block;font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:2.4rem;line-height:1;color:#8FB6E8}
|
|
.meter span{display:block;margin-top:3px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;opacity:.66;font-weight:700}
|
|
|
|
/* ── dispatch (steps as airmail envelopes) ── */
|
|
.dispatch{padding:80px 0 40px}
|
|
.sect{display:flex;align-items:flex-end;gap:16px;border-bottom:2px solid var(--ink);padding-bottom:10px}
|
|
.sect h2{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(2rem,5vw,3.4rem);text-transform:uppercase;line-height:.95}
|
|
.sect span{margin-left:auto;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-soft);font-weight:700;padding-bottom:5px}
|
|
|
|
.letters{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:22px;margin-top:30px}
|
|
.ltr{
|
|
background:var(--paper);border:2px solid var(--ink);position:relative;
|
|
padding:26px 26px 28px 40px;display:flex;flex-direction:column;
|
|
box-shadow:6px 7px 0 rgba(22,35,61,.12);transition:transform .2s,box-shadow .2s;
|
|
}
|
|
.ltr:hover{transform:translate(-3px,-3px);box-shadow:9px 10px 0 rgba(22,35,61,.16)}
|
|
/* chevron spine */
|
|
.ltr::before{
|
|
content:'';position:absolute;left:0;top:0;bottom:0;width:14px;
|
|
background:repeating-linear-gradient(-45deg,var(--red) 0 10px,var(--paper) 10px 20px,var(--blue) 20px 30px,var(--paper) 30px 40px);
|
|
border-right:1px solid var(--ink);
|
|
}
|
|
.ltr .mark{
|
|
position:absolute;right:20px;top:18px;width:56px;height:56px;border:2px solid var(--red);border-radius:50%;
|
|
display:grid;place-items:center;text-align:center;transform:rotate(-11deg);
|
|
font-size:8.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--red);font-weight:700;line-height:1.25;
|
|
}
|
|
.ltr h3{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:1.9rem;text-transform:uppercase;line-height:1;padding-right:70px}
|
|
.ltr .flag{
|
|
display:inline-block;margin-left:9px;vertical-align:5px;font-family:'Karla',sans-serif;font-weight:700;
|
|
font-size:9px;letter-spacing:.11em;text-transform:uppercase;background:var(--blue);color:#fff;padding:3px 8px;
|
|
}
|
|
.ltr .flag.-r{background:var(--red)}
|
|
.ltr code{display:block;font-family:ui-monospace,Menlo,monospace;font-size:11.5px;color:var(--blue);margin-top:7px;font-weight:600}
|
|
.ltr p{margin-top:12px;color:var(--ink-soft);font-size:.94rem}
|
|
.ltr .pen{font-family:'Caveat',cursive;font-size:1.2rem;color:var(--red);margin-top:10px;transform:rotate(-.8deg)}
|
|
.ltr ul{list-style:none;margin-top:auto;padding-top:16px}
|
|
.ltr li{font-size:.85rem;padding:6px 0 6px 18px;position:relative;border-top:1px dotted rgba(22,35,61,.24)}
|
|
.ltr li::before{content:'✈';position:absolute;left:0;color:var(--blue);font-size:9px;top:9px}
|
|
|
|
/* ── two routes ── */
|
|
.routes{background:var(--paper);border-top:2px solid var(--ink);border-bottom:2px solid var(--ink);padding:76px 0;margin-top:56px}
|
|
.rc{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:28px}
|
|
.rc div{border:2px solid var(--ink);padding:26px 24px}
|
|
.rc .-a{background:rgba(211,58,56,.06)}
|
|
.rc .-b{background:rgba(36,85,164,.06)}
|
|
.rc h4{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:1.5rem;text-transform:uppercase}
|
|
.rc ul{list-style:none;margin-top:14px}
|
|
.rc li{padding:9px 0 9px 24px;position:relative;font-size:.95rem;border-top:1px solid rgba(22,35,61,.14);color:var(--ink-soft)}
|
|
.rc li:first-child{border-top:none}
|
|
.rc .-a li::before{content:'✕';position:absolute;left:0;color:var(--red);font-weight:700}
|
|
.rc .-b li::before{content:'✓';position:absolute;left:0;color:var(--blue);font-weight:700}
|
|
|
|
/* ── regulations ── */
|
|
.regs{padding:78px 0}
|
|
.rg{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:0;margin-top:26px;border-top:2px solid var(--ink);border-left:2px solid var(--ink)}
|
|
.rg div{padding:22px 20px;border-right:2px solid var(--ink);border-bottom:2px solid var(--ink);background:var(--paper)}
|
|
.rg b{font-size:10px;letter-spacing:.15em;text-transform:uppercase;color:var(--red);font-weight:700}
|
|
.rg p{margin-top:9px;font-size:.94rem;color:var(--ink-soft)}
|
|
.rg p strong{color:var(--ink);font-weight:700}
|
|
|
|
/* ── install ── */
|
|
.install{padding:0 0 82px}
|
|
.term{margin-top:20px;background:var(--ink);color:#D6E2F2;padding:24px;
|
|
font-family:ui-monospace,Menlo,monospace;font-size:12.5px;line-height:2.05;overflow-x:auto}
|
|
.term .c{color:#7488A6}.term .k{color:#F0B06A}.term .p{color:#8FB6E8}
|
|
|
|
/* ── close ── */
|
|
.close{background:var(--ink);color:var(--paper);text-align:center;padding:92px 0}
|
|
.close h2{font-family:'Big Shoulders Display',sans-serif;font-weight:800;font-size:clamp(2.4rem,7vw,5.2rem);text-transform:uppercase;line-height:.9}
|
|
.close h2 em{font-style:normal;color:#8FB6E8}
|
|
.close .hand{display:block;margin-top:14px;font-size:1.5rem;color:#8FB6E8}
|
|
.close .btn{margin-top:24px;background:var(--red)}
|
|
.close .btn:hover{background:var(--paper);color:var(--ink)}
|
|
footer{background:var(--ink);color:rgba(251,250,246,.5);padding:0 0 28px;font-size:10px;letter-spacing:.15em;text-transform:uppercase;font-weight:700}
|
|
footer .wrap{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;border-top:1px dashed rgba(251,250,246,.24);padding-top:20px}
|
|
|
|
@media(max-width:700px){:root{--fr:8px}}
|
|
@media(max-width:820px){
|
|
.wrap{padding:0 20px}
|
|
.env{padding:26px 22px 28px}
|
|
.addr{grid-template-columns:1fr;gap:22px}
|
|
.rc{grid-template-columns:1fr}
|
|
.letters{grid-template-columns:1fr}
|
|
}
|
|
@media(prefers-reduced-motion:reduce){*{transition:none!important}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="frame-t" aria-hidden="true"></div>
|
|
<div class="frame-b" aria-hidden="true"></div>
|
|
<div class="frame-l" aria-hidden="true"></div>
|
|
<div class="frame-r" aria-hidden="true"></div>
|
|
|
|
<header class="top">
|
|
<div class="wrap">
|
|
<span class="brand">PLAN<i>2</i>CODE</span>
|
|
<span class="avion">Par Avion · Via Air Mail</span>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="hero">
|
|
<div class="wrap">
|
|
<div class="env">
|
|
<div class="pstamp"><div class="in"><b>2.0</b><span>Plan2Code</span><span>Postage</span></div></div>
|
|
<svg class="cancel" viewBox="0 0 210 110" aria-hidden="true">
|
|
<circle class="ring" cx="52" cy="55" r="42"/>
|
|
<text x="52" y="46" text-anchor="middle" font-size="10">SHIPPED</text>
|
|
<text x="52" y="62" text-anchor="middle" font-size="13" font-weight="700">2026</text>
|
|
<text x="52" y="76" text-anchor="middle" font-size="8">NO REWORK</text>
|
|
<path class="wv" d="M98,36 C118,28 138,44 158,36 C178,28 194,40 208,34"/>
|
|
<path class="wv" d="M98,50 C118,42 138,58 158,50 C178,42 194,54 208,48"/>
|
|
<path class="wv" d="M98,64 C118,56 138,72 158,64 C178,56 194,68 208,62"/>
|
|
<path class="wv" d="M98,78 C118,70 138,86 158,78 C178,70 194,82 208,76"/>
|
|
</svg>
|
|
|
|
<p class="kick">Spec-driven workflow for AI coding agents</p>
|
|
<h1>Send the plan.<br>The build <em>follows</em>.</h1>
|
|
|
|
<div class="addr">
|
|
<div>
|
|
<p class="to">Addressed to</p>
|
|
<p>Anyone who has watched an AI agent confidently build the wrong thing. You approve a plan, it becomes phase documents in your repo, and the agent works to those documents one phase at a time.</p>
|
|
</div>
|
|
<div class="acts">
|
|
<a class="btn" href="https://github.com/jparkerweb/plan2code">Install Plan2Code</a>
|
|
<a class="btn -o" href="#dispatch">Read the letters</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="meter">
|
|
<div class="wrap">
|
|
<div><b>90%</b><span>Confidence gate</span></div>
|
|
<div><b>11</b><span>Review dimensions</span></div>
|
|
<div><b>1</b><span>Chat per phase</span></div>
|
|
<div><b>0</b><span>Context pollution</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="dispatch wrap" id="dispatch">
|
|
<div class="sect"><h2>Six written letters</h2><span>Two optional</span></div>
|
|
|
|
<div class="letters">
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Opt<br>00</span>
|
|
<h3>Pathfinder<span class="flag">New in 2.0</span></h3>
|
|
<code>/plan2code-0-pathfinder</code>
|
|
<p>For an idea that arrives too foggy to plan. It charts the idea as a map of decision questions and clears exactly one per session until nothing is left to decide.</p>
|
|
<p class="pen">it never answers its own questions — that's the point</p>
|
|
<ul>
|
|
<li>One decision per file, one file per session</li>
|
|
<li>Research questions fan out to parallel agents</li>
|
|
<li>Clears at ≥18/25 on four confidence dimensions</li>
|
|
<li>Hands a hot plan draft to Step 1</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>01</span>
|
|
<h3>Plan</h3>
|
|
<code>/plan2code-1-plan</code>
|
|
<p>A real back-and-forth about what gets built. Requirements pulled apart, your codebase actually read, the stack confirmed rather than assumed.</p>
|
|
<ul>
|
|
<li>Functional and non-functional requirements</li>
|
|
<li>Integration points read from real source</li>
|
|
<li>Tech stack confirmed by explicit approval</li>
|
|
<li>Will not finalize below 90% confidence</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>02</span>
|
|
<h3>Document</h3>
|
|
<code>/plan2code-2-document</code>
|
|
<p>The plan stops being a conversation and becomes files — an overview plus one self-contained phase document per phase, cut into one-story-point tasks.</p>
|
|
<ul>
|
|
<li>overview.md and Phase 1…N.md land in your repo</li>
|
|
<li>One-point tasks with real checkboxes</li>
|
|
<li>Parallel groups marked for concurrent agents</li>
|
|
<li>Each phase readable with no prior context</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>03</span>
|
|
<h3>Implement</h3>
|
|
<code>/plan2code-3-implement</code>
|
|
<p>Build to the drawing, one phase per conversation. Planning context bleeding into implementation is where most agent drift starts.</p>
|
|
<p class="pen">reply “approved” — nothing advances on a guess</p>
|
|
<ul>
|
|
<li>Fresh conversation for every phase</li>
|
|
<li>Specs followed exactly as documented</li>
|
|
<li>Self-review against the spec before close</li>
|
|
<li>[/] claims prevent parallel-agent collisions</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Opt<br>✳</span>
|
|
<h3>Review<span class="flag -r">Second opinion</span></h3>
|
|
<code>/plan2code-review</code>
|
|
<p>An independent senior engineer with fresh eyes and no attachment to the code that just shipped. It reads every changed file completely and reports only what it can prove — file, line, and a concrete fix.</p>
|
|
<ul>
|
|
<li>Scope adapts: files, branch diff, or subsystem</li>
|
|
<li>All 11 dimensions reported, clean ones justified</li>
|
|
<li>Ranked Critical / Warning / Suggestion</li>
|
|
<li>Read-only until you reply H, A, or S 1,3,5</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<article class="ltr">
|
|
<span class="mark">Req<br>04</span>
|
|
<h3>Finalize</h3>
|
|
<code>/plan2code-4-finalize</code>
|
|
<p>Close it out. Every task audited against the spec it came from, a summary of what was built, docs checked for drift, and the folder filed away.</p>
|
|
<ul>
|
|
<li>Audit for tasks quietly left open</li>
|
|
<li>Summary of what was built and changed</li>
|
|
<li>README and other docs reconciled</li>
|
|
<li>Specs archived to specs--completed/</li>
|
|
</ul>
|
|
</article>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
<section class="routes">
|
|
<div class="wrap">
|
|
<div class="sect"><h2>Two routes</h2><span>Same destination</span></div>
|
|
<div class="rc">
|
|
<div class="-a">
|
|
<h4>Sent without an address</h4>
|
|
<ul>
|
|
<li>Coding starts, requirements arrive later</li>
|
|
<li>Design problems surface mid-build</li>
|
|
<li>Constant backtracking and rework</li>
|
|
<li>Context bloated with abandoned attempts</li>
|
|
<li>No way to prove requirements were met</li>
|
|
<li>Tokens burned on trial and error</li>
|
|
</ul>
|
|
</div>
|
|
<div class="-b">
|
|
<h4>Sent with a plan attached</h4>
|
|
<ul>
|
|
<li>The plan is approved before any code</li>
|
|
<li>Problems caught while they are still cheap</li>
|
|
<li>Implementation follows the drawing</li>
|
|
<li>Clean context, one phase at a time</li>
|
|
<li>Checkboxes prove what is done</li>
|
|
<li>Tokens spent building the agreed thing</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="regs wrap">
|
|
<div class="sect"><h2>Postal regulations</h2><span>Four · non-negotiable</span></div>
|
|
<div class="rg">
|
|
<div><b>Reg 01</b><p>A <strong>fresh conversation</strong> for each step, and each implementation phase.</p></div>
|
|
<div><b>Reg 02</b><p>No code until the plan hits <strong>90% confidence</strong>. The gate does not negotiate.</p></div>
|
|
<div><b>Reg 03</b><p><strong>Checkboxes are the state</strong>, not the chat. Any session resumes cold.</p></div>
|
|
<div><b>Reg 04</b><p>Reply <strong>approved</strong> to close a phase. Nothing advances on a guess.</p></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="install wrap">
|
|
<div class="sect"><h2>Installation</h2><span>Node 14+ · re-run to update</span></div>
|
|
<pre class="term"><span class="p">$</span> npx <span class="k">--allow-git=all</span> git+https://github.com/jparkerweb/plan2code.git</pre>
|
|
</section>
|
|
|
|
<section class="close">
|
|
<div class="wrap">
|
|
<h2>Post it once.<br><em>Then go outside.</em></h2>
|
|
<span class="hand">free, MIT, twenty seconds to install</span>
|
|
<br><a class="btn" href="https://github.com/jparkerweb/plan2code">Get Plan2Code</a>
|
|
</div>
|
|
</section>
|
|
|
|
<footer><div class="wrap"><span>Plan2Code v2.0.0</span><span>MIT</span><span>plan2code.jparkerweb.com</span></div></footer>
|
|
</body>
|
|
</html>
|