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 __tests__/root-static-csp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function loadWorker() {
console,
openNext: { fetch: openNextFetch },
withTiming: (handler: RootWorker['fetch']) => handler,
withPublicReadability: (handler: RootWorker['fetch']) => handler,
handleAgentEdge: () => null,
handleRolePatchAgentRoutes: () => null,
isDocumentRequest: () => true,
Expand Down
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"!**/.pages-deploy",
"!**/extension",
"!**/*.css",
"!**/design.html"
"!**/design.html",
"!src/lib/agent-surfaces"
]
},
"formatter": {
Expand Down
2 changes: 1 addition & 1 deletion knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"agent-edge.mjs",
"worker.mjs"
],
"ignore": ["open-next.config.ts"],
"ignore": ["open-next.config.ts", "src/lib/agent-surfaces/**"],
"ignoreIssues": { "src/components/ui/**": ["exports", "types"] },
"ignoreDependencies": [
"@mozilla/readability",
Expand Down
3 changes: 2 additions & 1 deletion landing-astro/src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const jsonLd = productJsonLd(SITE_URL);

<title>{title}</title>
<meta name="description" content={description} />
<meta name="ai-summary" content={description} />
<meta name="application-name" content="RolePatch" />
<meta name="author" content="RolePatch" />
<meta name="creator" content="RolePatch" />
Expand All @@ -38,7 +39,7 @@ const jsonLd = productJsonLd(SITE_URL);
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />

<link rel="canonical" href={canonicalUrl} />
<link rel="alternate" type="text/markdown" href="/index.md" />
<link rel="alternate" type="text/markdown" href={canonicalPath === '/' ? '/index.md' : `${canonicalPath}.md`} />
<link rel="alternate" type="text/plain" href="/llms.txt" />
<link rel="describedby" type="application/json" href="/api/ai" />

Expand Down
4 changes: 4 additions & 0 deletions landing-astro/src/lib/product.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { publicIdentity } from '../../../src/lib/public-identity';
const PRODUCT_DESCRIPTION =
'Tailor a resume to one job using claims supported by your experience, then review every proposed change before it becomes part of the application.';

Expand Down Expand Up @@ -39,8 +40,11 @@ export const PRODUCT_FAQS = [
export const productJsonLd = (siteUrl: string) => ({
'@context': 'https://schema.org',
'@graph': [
publicIdentity['@graph'][0],
{
'@type': 'WebSite',
'@id': `${siteUrl}/#app`,
publisher: { '@id': 'https://sarthakagrawal.dev/#person' },
name: 'RolePatch',
alternateName: ['Role Patch', 'rolepatch.com'],
url: siteUrl,
Expand Down
64 changes: 2 additions & 62 deletions landing-astro/src/pages/changelog.astro
Original file line number Diff line number Diff line change
@@ -1,79 +1,19 @@
---
import { PublicChangelog } from '../../../src/components/public-changelog';
import Layout from '@/layouts/Layout.astro';
import SiteFooter from '@/components/SiteFooter.astro';
import SiteHeader from '@/components/SiteHeader.astro';

const TITLE = 'RolePatch changelog — Verified product updates';
const DESCRIPTION =
'Verified RolePatch updates to guest workflows, job discovery, review-first application assistance, receipts, proof, and release checks.';
const sourceUrl = 'https://github.com/Significant-Hobbies/rolepatch';
const roadmapUrl = `${sourceUrl}/issues`;

const entries = [
{
date: 'July 11, 2026',
title: 'Guest workflows became more predictable',
body: 'The test environment now resets browser-local state between runs. That protects the same boundary unsigned users rely on when they keep resumes, searches, and application drafts on one device.',
},
{
date: 'July 4, 2026',
title: 'Job discovery moved into the product',
body: 'A LinkedIn-focused job browser added quick searches, posting signals, resume-aware ranking, visible match evidence, and reviewed batch queueing. Guests can search and prepare locally without being forced to sign in.',
},
{
date: 'July 4, 2026',
title: 'Application assistance became receipt-first',
body: 'The reviewed queue added Chrome-assisted ATS fill, guarded submit attempts, provider-aware blockers, field-level details, retry timelines, and copyable audit summaries. Unattended bulk apply remains out of scope.',
},
{
date: 'July 4, 2026',
title: 'Proof and public release checks shipped',
body: 'RolePatch added a source-backed Proof surface and a release preflight covering type safety, formatting, tests, the extension build, the Cloudflare build, public routes, and responsive browser journeys.',
},
];
---

<Layout title={TITLE} description={DESCRIPTION} canonicalPath="/changelog">
<div class="rolepatch-page">
<SiteHeader active="changelog" />
<main>
<section class="page-hero paper-grid">
<div class="site-shell">
<p class="section-label">Verified product history</p>
<h1>What changed, and why it matters.</h1>
<p>
Shipped changes live here. Planned work stays in the public issue tracker, where it
cannot be mistaken for a finished feature.
</p>
</div>
</section>

<section class="page-section" aria-label="RolePatch releases">
<div class="site-shell">
<div class="release-list">
{entries.map((entry) => (
<article class="release-item">
<time class="release-date">{entry.date}</time>
<div>
<h2>{entry.title}</h2>
<p>{entry.body}</p>
</div>
</article>
))}
</div>
<div class="page-cta">
<div>
<h2>Inspect the work behind the claims.</h2>
<p>The canonical repository and its issue tracker are public.</p>
</div>
<div class="hero-actions">
<a href={sourceUrl} class="primary-action">View source <span aria-hidden="true">↗</span></a>
<a href={roadmapUrl} class="secondary-action">Open roadmap <span aria-hidden="true">→</span></a>
</div>
</div>
</div>
</section>
</main>
<PublicChangelog />
<SiteFooter />
</div>
</Layout>
86 changes: 3 additions & 83 deletions landing-astro/src/pages/docs.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import { PublicDocs } from '../../../src/components/public-docs';
import Layout from '@/layouts/Layout.astro';
import SiteFooter from '@/components/SiteFooter.astro';
import SiteHeader from '@/components/SiteHeader.astro';
Expand All @@ -7,94 +8,13 @@ const TITLE = 'RolePatch developer docs — Public discovery surfaces';
const DESCRIPTION =
'Documentation for RolePatch’s read-only public catalog, LLM indexes, Markdown negotiation, OpenAPI schema, typed errors, and version policy.';

const endpoints = [
['/api/ai', 'JSON catalog of every public HTML surface and same-origin Markdown alternate.'],
['/api/public/v1/surfaces/{id}', 'Versioned JSON lookup for one catalog surface. This link uses the home surface as a working example; an unknown id returns a typed problem response.', '/api/public/v1/surfaces/home'],
['/llms.txt', 'Compact product guidance, best-fit use cases, boundaries, access, and discovery links.'],
['/llms-full.txt', 'Expanded product brief for agents that need the full product contract.'],
['/index.md', 'Canonical Markdown explanation of product purpose, evidence rules, access, and state.'],
['/openapi.json', 'OpenAPI 3.1 description of these read-only discovery routes.'],
['/sitemap.xml', 'Canonical public route inventory for crawlers.'],
] as const;

---

<Layout title={TITLE} description={DESCRIPTION} canonicalPath="/docs">
<div class="rolepatch-page">
<SiteHeader active="docs" />
<main>
<section class="page-hero paper-grid">
<div class="site-shell">
<p class="section-label">Public discovery interface</p>
<h1>Read the product contract. Do not automate the applicant.</h1>
<p>
RolePatch publishes a small, unauthenticated, read-only interface so agents can
discover the product and understand its limits. Resume tailoring and application
actions remain inside the reviewed user workflow.
</p>
</div>
</section>

<section class="page-section">
<div class="site-shell docs-layout">
<div class="docs-intro">
<p class="section-label">Endpoints</p>
<h2>Seven public routes. No mutation API.</h2>
<p>
Use GET or HEAD. These routes require no token or account. They describe RolePatch;
they do not accept a resume, spend credits, fill an ATS, or submit an application.
</p>
</div>
<div class="endpoint-list">
{endpoints.map(([path, body, href = path]) => (
<article>
<a href={href}><code>{path}</code></a>
<p>{body}</p>
</article>
))}
</div>
</div>
</section>

<section class="page-section paper-grid">
<div class="site-shell docs-notes">
<article>
<p class="section-label">Markdown negotiation</p>
<h2>Ask for Markdown at the page URL.</h2>
<p>
Send <code>Accept: text/markdown</code> to any cataloged public page, or request its
explicit <code>.md</code> alternate. Negotiated responses include{' '}
<code>Vary: Accept</code> so HTML and Markdown cannot poison one another in a cache.
</p>
</article>
<article>
<p class="section-label">Error model</p>
<h2>Discovery errors are structured.</h2>
<p>
Unsupported methods and missing discovery routes return{' '}
<code>application/problem+json</code> with a stable code, status, detail, and
resolution hint. Ordinary product routes keep their own application contracts.
</p>
</article>
<article>
<p class="section-label">Version policy</p>
<h2>Breaking changes get a new major contract.</h2>
<p>
The OpenAPI <code>info.version</code> follows semantic versioning. A breaking change
gets a new major version; the previous contract remains available for at least 90
days with <code>Deprecation</code> and <code>Sunset</code> response headers.
</p>
</article>
<article>
<p class="section-label">Non-goals</p>
<h2>No public agent can apply on your behalf.</h2>
<p>
There is no public mutation API, MCP tool, payment-by-agent rail, CAPTCHA bypass, or
unattended file upload. Those absences preserve the review-first product boundary.
</p>
</article>
</div>
</section>
</main>
<PublicDocs />
<SiteFooter />
</div>
</Layout>
34 changes: 2 additions & 32 deletions landing-astro/src/pages/faq.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import { PublicFaq } from '../../../src/components/public-faq';
import Layout from '@/layouts/Layout.astro';
import SiteFooter from '@/components/SiteFooter.astro';
import SiteHeader from '@/components/SiteHeader.astro';
Expand All @@ -22,38 +23,7 @@ const faqJsonLd = {
<Layout title={TITLE} description={DESCRIPTION} canonicalPath="/faq">
<div class="rolepatch-page">
<SiteHeader active="faq" />
<main>
<section class="page-hero paper-grid">
<div class="site-shell">
<p class="section-label">RolePatch FAQ</p>
<h1>Straight answers before you trust it with a real application.</h1>
<p>
What RolePatch may change, what it must leave alone, where your records live, what
costs money, and where application assistance stops.
</p>
</div>
</section>

<section class="page-section">
<div class="site-shell">
<div class="faq-page-list">
{PRODUCT_FAQS.map((faq) => (
<article>
<h2>{faq.q}</h2>
<p>{faq.a}</p>
</article>
))}
</div>
<div class="page-cta">
<div>
<h2>Bring the job. Keep the claims yours.</h2>
<p>Start with a guest workspace, then decide whether account-backed persistence belongs in your search.</p>
</div>
<a href="/resume-builder" class="primary-action">Open RolePatch <span aria-hidden="true">↗</span></a>
</div>
</div>
</section>
</main>
<PublicFaq />
<script type="application/ld+json" set:html={JSON.stringify(faqJsonLd)} is:inline />
<SiteFooter />
</div>
Expand Down
1 change: 1 addition & 0 deletions landing-astro/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ content.page.jsonLd = [jsonLd, {
<Base {...baseProps(content)}>
<Fragment slot="head">
<meta name="application-name" content="RolePatch" />
<meta name="ai-summary" content={content.page.description} />
<meta name="author" content="RolePatch" />
<meta name="creator" content="RolePatch" />
<meta name="keywords" content="resume tailor, AI resume, ATS score, resume diff, job application, cover letter generator, resume keywords, resume optimizer, job fit score, interview prep, STAR stories" />
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"brace-expansion@>=2.0.0 <2.1.7": "2.1.7",
"brace-expansion@>=4.0.0 <5.0.12": "5.0.12",
"brace-expansion@>=5.0.0 <5.0.12": "5.0.12",
"undici@>=7.0.0 <7.29.1": "7.29.1",
"devalue@<=5.9.2": "5.9.3",
"js-yaml@>=4.0.0 <4.3.2": "4.3.2",
"svgo@>=4.0.0 <4.1.0": "4.1.0",
Expand All @@ -26,7 +25,11 @@
"astro@7.2.8>vite": "8.2.4",
"dompurify@<3.4.17": "3.4.17",
"http-cache-semantics": "4.3.0",
"glob@>=10.2.0 <10.5.0": "10.5.0"
"glob@>=10.2.0 <10.5.0": "10.5.0",
"undici@>=8.0.0 <8.12.2": "8.12.2",
"zod@>=4.0.0 <4.6.6": "4.6.6",
"body-parser@>=2.0.0 <2.4.0": "2.4.0",
"undici@>=7.0.0 <7.30.1": "7.30.1"
},
"patchedDependencies": {
"@saas-maker/templates@0.1.18": "patches/saas-maker-templates-footer-retry-0.1.18.patch",
Expand Down Expand Up @@ -103,7 +106,7 @@
"next": "16.4.1",
"pdf-parse": "^2.4.5",
"posthog-js": "^1.407.3",
"puppeteer-core": "^24.42.0",
"puppeteer-core": "25.16.0",
"react": "19.2.8",
"react-diff-viewer-continued": "^4.4.0",
"react-dom": "19.2.8",
Expand All @@ -113,7 +116,7 @@
"uuid": "^13.0.1",
"web-vitals": "^4.2.4",
"workers-ai-provider": "3.3.1",
"zod": "^4.4.3"
"zod": "4.6.6"
},
"devDependencies": {
"@biomejs/biome": "2.5.5",
Expand Down
Loading
Loading