Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<a href="/cookies">Cookie Policy</a>
<a href="/terms">Terms of Service</a>
<a href="/aup">Acceptable Use</a>
<a href="/publisher-agreement">Publisher Agreement</a>
<a href="javascript:void(0)" id="cookie-preferences-link">Cookie Preferences</a>
<a href="/press">Press Kit</a>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/plain/publish.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import PlainLayout from '../../layouts/PlainLayout.astro';
<li>Methods: each method an agent can call — name (&lt;ns&gt;.&lt;verb&gt;), HTTP route, latency class (fast under 5s, medium up to 15s, slow up to 1 minute), description, and parameters.</li>
<li>Listing: display name, description, license, and categories for the store page.</li>
<li>Vendor: who you are, how autonomous agents should use the app, and the list of capabilities.</li>
<li>Review and submit: the server builds, signs, and verifies the adapter and stores it for review.</li>
<li>Review and submit: sign the Publisher Release Agreement (type your full legal name and check the box), then the server builds, signs, and verifies the adapter and stores it for review.</li>
</ul>

<h2>Publish by PR</h2>
Expand All @@ -46,7 +46,7 @@ import PlainLayout from '../../layouts/PlainLayout.astro';
<ul>
<li>An existing HTTP API. CLI/binary apps are coming soon.</li>
<li>A valid email (browser flow) for the confirmation and the review decision.</li>
<li>You confirm you have the right to publish the app and agree to the Terms and Acceptable Use Policy.</li>
<li>You confirm you have the right to publish the app and agree to the Terms, Acceptable Use Policy, and Publisher Release Agreement, which you sign at the final step. See https://pilotprotocol.network/publisher-agreement</li>
</ul>

</PlainLayout>
53 changes: 49 additions & 4 deletions src/pages/publish.astro
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const canonicalUrl = 'https://pilotprotocol.network/publish';
<li><b>Your keys stay yours.</b> Secrets are never collected here — operators supply them at install time.</li>
<li><b>Every submission is reviewed</b> by our team before it appears in the store.</li>
<li><b>We'll keep you posted by email</b> — a confirmation when you submit, and again when your app is approved or needs changes.</li>
<li>By submitting you confirm you have the right to publish this app and agree to the <a href="/terms">Terms</a> and <a href="/aup">Acceptable Use Policy</a>.</li>
<li><b>You sign a short release at the end.</b> Before submitting you confirm you have the right to publish this app, grant us permission to use your name and the app's name to list it, and agree to the <a href="/terms">Terms</a>, <a href="/aup">Acceptable Use Policy</a>, and <a href="/publisher-agreement">Publisher Release Agreement</a>.</li>
</ul>

<p class="how">How it works: <b>describe your app → verify your email → we build &amp; verify the adapter → our team reviews → it's live in the app store.</b></p>
Expand Down Expand Up @@ -196,6 +196,14 @@ const canonicalUrl = 'https://pilotprotocol.network/publish';
#publish .banner.ok { background:#eef7f0; border:1px solid #b9dcc0; color:oklch(0.42 0.16 145); }
#publish .explain { background:#f3f2ec; border:1px solid var(--c-line); border-radius:11px; padding:14px 16px; font-size:14px; color:var(--c-dim); margin-bottom:18px; line-height:1.5; }
#publish .explain code { color:oklch(0.5 0.17 142); font-family:var(--mono,monospace); }

/* ── release agreement (final step) ── */
#publish .card.release { padding:26px 30px; }
#publish .release-h { font-size:18px; font-weight:650; margin:0 0 10px; color:var(--c-ink); }
#publish .release-p { font-size:15px; line-height:1.55; color:var(--c-dim); margin:0 0 22px; }
#publish .release a { color:var(--c-acc); text-decoration:underline; }
#publish .agree { display:flex; gap:12px; align-items:flex-start; font-size:15px; line-height:1.5; color:var(--c-ink); cursor:pointer; }
#publish .agree input { width:auto; margin:2px 0 0; flex:none; accent-color:var(--c-acc); }
</style>

<script>
Expand All @@ -214,6 +222,10 @@ const blankParam = () => ({ name: '', type: 'string', required: false, descripti
const blankMethod = () => ({ name: '', http: { verb: 'GET', path: '' }, latency: '', description: '', params: [blankParam()] });
const blankHeader = () => ({ name: '', value: '' });

// Version of the Publisher Release Agreement the publisher signs at submit time.
// Bump this (and the page at /publisher-agreement) whenever the agreement changes.
const AGREEMENT_VERSION = '2026-06-20';

let state = load() || {
email: '',
id: 'io.pilot.', version: '', description: '',
Expand All @@ -222,7 +234,10 @@ let state = load() || {
methods: [blankMethod()],
listing: { display_name: '', tagline: '', app_description: '', license: '', homepage: '', source_url: '', categories: '', keywords: '', requires_binary: false, binary_url: '' },
vendor: { name: '', url: '', agent_usage: '', capabilities: '' },
release: { signer_name: '', agreed: false },
};
// Drafts saved before the release step existed won't carry a release object.
if (!state.release) state.release = { signer_name: '', agreed: false };

function load() { try { return JSON.parse(localStorage.getItem(LS)); } catch { return null; } }
function save() { localStorage.setItem(LS, JSON.stringify(state)); }
Expand All @@ -244,6 +259,11 @@ function submission() {
})),
listing: { ...state.listing, categories: csv(state.listing.categories), keywords: csv(state.listing.keywords) },
vendor: { ...state.vendor, contact: state.email },
release: {
agreement_version: AGREEMENT_VERSION,
signer_name: state.release.signer_name,
agreed: !!state.release.agreed,
},
};
}

Expand Down Expand Up @@ -366,7 +386,15 @@ const STEPS_HTML = [
<div id="submit-banner"></div>
<div class="card"><table class="review-tbl" id="review-tbl"></table></div>
<div class="preview" id="preview"></div>
<div class="navrow"><button class="back" id="back" type="button">← Back</button><button class="btn" id="submit" type="button">Submit for review</button></div>`,
<div class="card release">
<h3 class="release-h">Release agreement</h3>
<p class="release-p">Before your app can be listed, you sign the <a href="/publisher-agreement" target="_blank" rel="noopener">Publisher Release Agreement</a>. In short: you confirm you have the right to publish this app, you grant Pilot Protocol a license to use your name and the app's name to list and promote it in the app store and on our website, and you release us from claims arising from that authorized use. Please read the full agreement before signing.</p>
<div class="field"><label>Full legal name (your signature) ${info('Typing your name and submitting signs the Publisher Release Agreement electronically — it carries the same legal effect as a handwritten signature.')}</label>
<input id="f-signer" autocomplete="name" placeholder="Jane Doe" value="${esc(state.release.signer_name)}"><div class="err" id="e-signer"></div></div>
<label class="agree"><input type="checkbox" id="f-agree" ${state.release.agreed?'checked':''}><span>I have read and agree to the <a href="/publisher-agreement" target="_blank" rel="noopener">Publisher Release Agreement</a>, and I confirm I am authorized to publish this app and to grant the rights it describes.</span></label>
<div class="err" id="e-agree"></div>
</div>
<div class="navrow"><button class="back" id="back" type="button">← Back</button><button class="btn" id="submit" type="button" disabled>Submit for review</button></div>`,
];

function nav() {
Expand Down Expand Up @@ -453,7 +481,17 @@ function wire() {
['display_name','tagline','app_description','license','homepage','source_url','categories','keywords'].forEach(k=>bindVal('f-l-'+k,v=>state.listing[k]=v));
}
if (cur==='Vendor'){ ['name','url','agent_usage','capabilities'].forEach(k=>bindVal('f-v-'+k,v=>state.vendor[k]=v)); }
if (cur==='Review'){ renderReview(); document.getElementById('submit').onclick=doSubmit; }
if (cur==='Review'){
renderReview();
const signer=document.getElementById('f-signer');
const agree=document.getElementById('f-agree');
const submit=document.getElementById('submit');
const syncRelease=()=>{ if(submit) submit.disabled=!(state.release.signer_name.trim() && state.release.agreed); };
if(signer) signer.addEventListener('input',()=>{ state.release.signer_name=signer.value; save(); show('e-signer',''); renderReview(); syncRelease(); });
if(agree) agree.addEventListener('change',()=>{ state.release.agreed=agree.checked; save(); show('e-agree',''); syncRelease(); });
syncRelease();
if(submit) submit.onclick=doSubmit;
}
}

// ── validation (client mirror of the server's; server is authoritative) ──
Expand Down Expand Up @@ -504,15 +542,22 @@ function renderReview(){
['App type','HTTP API'],
['Vendor',s.vendor.name+(s.vendor.url?' · '+s.vendor.url:'')],['Email',s.email],
['Agent usage',s.vendor.agent_usage],['Capabilities',s.vendor.capabilities],
['Signed by',s.release.signer_name],
];
document.getElementById('review-tbl').innerHTML=rows.map(([k,v])=>`<tr><th>${esc(k)}</th><td>${v||'<span style="color:var(--ink-faint)">—</span>'}</td></tr>`).join('');
}

async function doSubmit(){
const btn=document.getElementById('submit'); const banner=document.getElementById('submit-banner');
// The release agreement must be signed before we submit (the button is also
// disabled until then; this is the authoritative guard).
if(!state.release.signer_name.trim()){ show('e-signer','Type your full legal name to sign the release agreement'); return; }
if(!state.release.agreed){ show('e-agree','You must agree to the Publisher Release Agreement to submit'); return; }
const payload=submission();
payload.release.signed_at=new Date().toISOString();
btn.disabled=true; banner.innerHTML='<div class="banner">Building, signing, and verifying on the server…</div>';
try {
const r=await fetch(API+'/api/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(submission())});
const r=await fetch(API+'/api/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)});
const d=await r.json();
if(r.ok){ banner.innerHTML=`<div class="banner ok"><b>Submitted ✓</b> — case <code>${esc(d.case_id)}</code> is now <b>pending</b> review. The server built, signed, and verified your adapter.</div>`; localStorage.removeItem(LS); }
else { const errs=(d.errors||[d.error||'submission failed']); banner.innerHTML=`<div class="banner bad"><b>Fix these:</b><ul>${errs.map(e=>`<li>${esc(e)}</li>`).join('')}</ul></div>`; btn.disabled=false; }
Expand Down
93 changes: 93 additions & 0 deletions src/pages/publisher-agreement.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
import BaseHead from '../components/BaseHead.astro';
import Nav from '../components/Nav.astro';
import Footer from '../components/Footer.astro';
import '../styles/system.css';

const title = "Publisher Release Agreement — Pilot Protocol";
const description = "The agreement every publisher signs when submitting an app to the Pilot app store: a license to use the app and publisher name in the store and on the website, and a release of claims arising from that authorized use.";
const canonicalUrl = "https://pilotprotocol.network/publisher-agreement";
---
<!DOCTYPE html>
<html lang="en">
<head>
<BaseHead title={title} description={description} canonicalUrl={canonicalUrl} />
</head>
<body>

<Nav />

<main class="prose" style="padding: 96px 32px 80px; max-width: 760px; margin: 0 auto;">
<p class="breadcrumb"><a href="/">Home</a> <span class="sep">/</span> Publisher Release Agreement</p>

<h1>Publisher <em>Release Agreement</em></h1>
<p class="article-meta" style="display:flex;gap:14px;font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-dim);padding:14px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin:0 0 36px;">
Version 2026-06-20 · Effective: June 20, 2026
</p>

<p>This Publisher Release Agreement ("Agreement") is a binding agreement between <strong>Vulture Labs</strong> ("Pilot Protocol," "we," "us," "our") and the person or entity submitting an app for publication ("Publisher," "you," "your"). You accept this Agreement at the moment you sign and submit an app through the publish flow at <a href="/publish">pilotprotocol.network/publish</a> or by pull request. <strong>If you do not agree, do not submit an app.</strong></p>

<p>This Agreement supplements, and does not replace, our <a href="/terms">Terms of Service</a> and <a href="/aup">Acceptable Use Policy</a>, which are incorporated here by reference. Capitalized terms not defined here have the meanings given in the Terms of Service.</p>

<h2>1. Definitions</h2>
<ul>
<li><strong>App</strong> — the application, HTTP API, or service you submit for publication, together with the methods, listing copy, descriptions, and metadata you provide about it.</li>
<li><strong>App Store</strong> — the Pilot Protocol app store and catalogue, through which agents discover and install apps.</li>
<li><strong>Marks</strong> — your name (and, where you submit on behalf of an organization, that organization's name), the App's name, and any trademarks, service marks, logos, and brand assets you provide or reference in your Submission.</li>
<li><strong>Submission</strong> — everything you supply through the publish flow, including the App description, methods, listing, vendor information, and your verified email address.</li>
</ul>

<h2>2. Your Representations &amp; Warranties</h2>
<p>By signing and submitting, you represent and warrant that:</p>
<ul>
<li>You have the full right, power, and authority to publish the App and to enter into this Agreement, and — where you sign on behalf of an organization — that you are authorized to bind that organization.</li>
<li>You own or have all necessary rights, licenses, and permissions in the App, the Marks, and everything in your Submission, and publishing them through Pilot Protocol does not and will not infringe, misappropriate, or violate the intellectual property, privacy, publicity, or other rights of any third party.</li>
<li>The Submission is accurate and not misleading, and the App does not violate the <a href="/aup">Acceptable Use Policy</a> or any applicable law.</li>
</ul>

<h2>3. License to Use Your Name &amp; Marks</h2>
<p>You grant Pilot Protocol and Vulture Labs a <strong>non-exclusive, worldwide, royalty-free, sublicensable license</strong> to use, reproduce, display, and distribute the Marks and the contents of your Submission for the purpose of:</p>
<ul>
<li>Listing, hosting, displaying, and distributing the App through the App Store;</li>
<li>Identifying you and the App on pilotprotocol.network and in the App Store catalogue and listings; and</li>
<li>Referencing the App and the Marks in reasonable marketing and promotional materials about the Pilot Protocol network and App Store (for example, store cards, directory entries, and announcements).</li>
</ul>
<p>This license is limited to those purposes. It does not transfer ownership of the Marks — you keep all right, title, and interest in them — and it does not authorize any use that suggests your endorsement of unrelated products. We will follow any reasonable, specific brand-usage guidelines you provide in your Submission to the extent practical.</p>

<h2>4. Release &amp; Covenant Not to Sue</h2>
<p>To the fullest extent permitted by law, you <strong>release, waive, and discharge</strong> Pilot Protocol, Vulture Labs, and their officers, directors, employees, agents, and successors (the "Released Parties") from, and <strong>covenant not to sue</strong> the Released Parties on, any and all claims, demands, damages, liabilities, costs, and causes of action — whether known or unknown — arising out of or relating to:</p>
<ul>
<li>The exercise of the license granted in Section 3, including the use of the Marks and your name in the App Store, on pilotprotocol.network, and in related promotional materials;</li>
<li>The listing, display, hosting, distribution, review, approval, rejection, or removal of the App; and</li>
<li>The generation, signing, and verification of an adapter for your App as part of the publish flow.</li>
</ul>
<p>This release does not extend to claims arising from our gross negligence, willful misconduct, or fraud, and it does not waive any right that cannot be waived under applicable law. Nothing in this Section limits your own ownership of the Marks or your right to enforce them against third parties.</p>

<h2>5. Our Discretion</h2>
<p>Publication is not guaranteed. We may review, decline, request changes to, suspend, remove, or delist any App or Submission at our sole discretion — including for violations of the Terms of Service or Acceptable Use Policy — with or without notice. We are under no obligation to publish, promote, or continue distributing any App.</p>

<h2>6. Indemnification</h2>
<p>You agree to indemnify and hold harmless the Released Parties from any third-party claims, damages, liabilities, and expenses (including reasonable legal fees) arising from the App, your Submission, your use of the publish flow, your breach of the representations in Section 2, or your violation of any third-party rights.</p>

<h2>7. Term &amp; Termination</h2>
<p>This Agreement takes effect when you sign and submit and continues for as long as the App is listed. You may request removal of the App at any time by contacting us at <a href="mailto:founders@pilotprotocol.network">founders@pilotprotocol.network</a>; we will delist it within a reasonable period. The license in Section 3 ends on delisting, except that (a) we may retain and use records of the Submission as needed for security, audit, and legal purposes, and (b) copies already distributed to operators before removal are not recalled. Sections 2, 4, 6, and 8 survive termination.</p>

<h2>8. Disclaimers, Liability &amp; Governing Law</h2>
<p>The App Store and publish flow are provided "as is" and "as available," and the warranty disclaimers and limitation of liability in our <a href="/terms">Terms of Service</a> apply to this Agreement in full. This Agreement is governed by the laws of the <strong>State of Delaware, United States</strong>, without regard to its conflict-of-laws principles, and any dispute will be resolved exclusively in the state or federal courts located in Delaware. Before initiating formal proceedings, you agree to contact us and attempt to resolve the dispute informally for at least thirty (30) days.</p>

<h2>9. Electronic Signature</h2>
<p>When you type your full legal name and submit, you are signing this Agreement electronically. You agree that your typed name, together with the timestamp and the App identifier recorded at submission, constitutes your signature and has the same legal effect as a handwritten signature. We record the version of this Agreement you accepted.</p>

<h2>10. Contact</h2>
<p>Questions about this Agreement?</p>
<p>Email: <a href="mailto:founders@pilotprotocol.network">founders@pilotprotocol.network</a></p>

<p style="margin-top:48px;padding-top:24px;border-top:1px solid var(--line);font-size:14px;color:var(--ink-dim);">
<em>This Agreement is provided for transparency and operational clarity. It does not constitute legal advice. If you are a legal professional reviewing this document, please direct feedback to <a href="mailto:founders@pilotprotocol.network">founders@pilotprotocol.network</a>.</em>
</p>
</main>

<Footer />

</body>
</html>
2 changes: 1 addition & 1 deletion src/pages/sitemap.xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function routeFromKey(key: string): string {
}

const REFERENCE = new Set(['error-codes', 'troubleshooting', 'diagnostics', 'configuration']);
const LEGAL = new Set(['/privacy', '/cookies', '/terms', '/aup']);
const LEGAL = new Set(['/privacy', '/cookies', '/terms', '/aup', '/publisher-agreement']);

function priorityFor(loc: string): { p: number; freq: string } {
if (loc === '/') return { p: 1.0, freq: 'weekly' };
Expand Down
Loading