From 7663d8e61e12cd0ea8213e8d52afeb51614b5b57 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Fri, 31 Jul 2026 04:12:07 +0530 Subject: [PATCH] keep Reader sitemap HTML-only --- PROJECT_STATUS.md | 4 +++ public/api-ai.json | 14 ++++++++ public/changelog.md | 32 +++++++++++++++++ public/faq.md | 41 ++++++++++++++++++++++ public/llms-full.txt | 2 ++ public/llms.txt | 3 ++ public/sitemap.xml | 4 +-- src/agent-edge.mjs | 18 ++++++++-- src/agent-surfaces.test.ts | 70 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 public/changelog.md create mode 100644 public/faq.md create mode 100644 src/agent-surfaces.test.ts diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md index 0fbd7e6..ccd66b3 100644 --- a/PROJECT_STATUS.md +++ b/PROJECT_STATUS.md @@ -18,6 +18,10 @@ maintenance-first support. ## Timeline +- **2026-07-31:** Kept the public sitemap limited to the four canonical HTML + pages while retaining six machine resources through robots, llms, and the + agent catalog. Explicit tests now enforce sitemap, catalog, and Markdown + parity; production deployment remains separate. - **2026-07-31:** Added locally verified Open Graph/Twitter image metadata and SoftwareApplication structured data to the public landing layout; production deployment remains separate. diff --git a/public/api-ai.json b/public/api-ai.json index ebbdbdb..4e90fb2 100644 --- a/public/api-ai.json +++ b/public/api-ai.json @@ -18,6 +18,20 @@ "kind": "spa", "description": "Product home" }, + { + "id": "faq", + "url": "https://read.significanthobbies.com/faq", + "md": "https://read.significanthobbies.com/faq.md", + "kind": "static", + "description": "Frequently asked questions" + }, + { + "id": "changelog", + "url": "https://read.significanthobbies.com/changelog", + "md": "https://read.significanthobbies.com/changelog.md", + "kind": "static", + "description": "Verified product history" + }, { "id": "login", "url": "https://read.significanthobbies.com/login", diff --git a/public/changelog.md b/public/changelog.md new file mode 100644 index 0000000..a69826a --- /dev/null +++ b/public/changelog.md @@ -0,0 +1,32 @@ +# Reader changelog + +Meaningful improvements to saving, reading, annotating, and revisiting research. + +## 2026-07-13 — RSS and Atom reading joined the library + +- Authenticated readers can import OPML, manage feeds, refresh them, and track + unread items. +- Feed items can be saved into the article and PDF library for annotation and + later research. + +## 2026-07-03 — Memory capture became durable + +- Saved research memories gained authenticated persistence, search, and a + dedicated reading surface. +- Existing browser memories can be imported into the account-backed + collection. + +## 2026-07-02 — Safer failure recovery + +- Unhandled API and Worker failures now return controlled responses. +- A React error boundary provides a recovery path when a page cannot render. + +## 2026-06-20 — Reader moved to a faster app shell + +- Reader moved to Vite and React with a focused Hono Worker while preserving + its production identity. +- Articles, PDFs, highlights, notes, boards, lists, search, and AI-assisted + reading stayed together in one library. + +[Roadmap](https://github.com/Significant-Hobbies/reader/issues) · +[Source](https://github.com/Significant-Hobbies/reader) diff --git a/public/faq.md b/public/faq.md new file mode 100644 index 0000000..9a9c159 --- /dev/null +++ b/public/faq.md @@ -0,0 +1,41 @@ +# Reader FAQ + +Reader is a personal research library for capturing web articles and PDFs, +reading without distractions, preserving highlights and notes, and using AI +over sources you choose. + +## Capture and reading + +Paste an article URL or use the Chrome extension to save the current page. +Reader cleans web pages with Mozilla Readability. Uploaded PDFs join the same +library and have their text extracted so they can be searched and discussed. + +## Organisation + +Tags provide cross-cutting labels, lists group related sources, and boards give +projects a Kanban-style workflow such as “to read,” “reading,” and “done.” +Full-text search covers saved article bodies, PDF text, titles, and notes. + +## Highlights, notes, and progress + +Highlights anchor to the selected text so they persist across visits. Notes +live beside the source, and boards can track reading progress across a research +project. + +## AI assistance + +Reader can summarize an open article or PDF and answer questions using its +extracted text. You can bring an OpenAI, Anthropic, or Gemini key stored in the +browser, use the Free AI gateway, or use the local development bridge. Reader +does not store browser-held provider keys on its server. + +## Accounts and privacy + +The browser-local library works without an account. Google sign-in enables the +account-backed library and sync. Saved articles, PDFs, annotations, lists, +boards, and AI conversations remain private and are excluded from the public +sitemap and agent catalog. + +[Open Reader](https://read.significanthobbies.com/) · +[Sign in](https://read.significanthobbies.com/login) · +[View the changelog](https://read.significanthobbies.com/changelog) diff --git a/public/llms-full.txt b/public/llms-full.txt index a1fb3ca..ab2a57c 100644 --- a/public/llms-full.txt +++ b/public/llms-full.txt @@ -21,6 +21,8 @@ Personal libraries require auth and are not agent-indexed. Public marketing surf ## Product links - Home: https://read.significanthobbies.com/ — App (auth for library) +- FAQ: https://read.significanthobbies.com/faq — Frequently asked questions +- Changelog: https://read.significanthobbies.com/changelog — Verified product history - Login: https://read.significanthobbies.com/login — Sign in ## Machine surfaces diff --git a/public/llms.txt b/public/llms.txt index 98601e5..6172cf2 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -6,12 +6,15 @@ - [Home](https://read.significanthobbies.com/): App (auth for library) - [FAQ](https://read.significanthobbies.com/faq): Frequently asked questions +- [Changelog](https://read.significanthobbies.com/changelog): Verified product history - [Login](https://read.significanthobbies.com/login): Sign in ## Machine surfaces - [Agent catalog](https://read.significanthobbies.com/api/ai): JSON inventory of public surfaces - [Homepage markdown](https://read.significanthobbies.com/index.md): Product brief without JS +- [Full agent brief](https://read.significanthobbies.com/llms-full.txt): Complete product and privacy context +- [HTML sitemap](https://read.significanthobbies.com/sitemap.xml): Canonical public pages - [This index](https://read.significanthobbies.com/llms.txt) ## Optional diff --git a/public/sitemap.xml b/public/sitemap.xml index 89838c7..d367656 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,7 +1,7 @@ https://read.significanthobbies.com/ - https://read.significanthobbies.com/index.md - https://read.significanthobbies.com/llms.txt + https://read.significanthobbies.com/faq + https://read.significanthobbies.com/changelog https://read.significanthobbies.com/login diff --git a/src/agent-edge.mjs b/src/agent-edge.mjs index 44b08b7..bd1db72 100644 --- a/src/agent-edge.mjs +++ b/src/agent-edge.mjs @@ -13,8 +13,8 @@ export const AGENT_SURFACE = { "name": "Reader", "url": "https://read.significanthobbies.com", - "llmsFullTxt": "# Reader — full agent brief\n\nResearch library: capture, annotate, and AI-chat over your reading — private by default.\n\n## Index\n\n# Reader\n\nResearch library for capture, annotation, and AI chat over your reading.\n\n## Privacy\n\nPersonal libraries require auth and are not agent-indexed. Public marketing surfaces only.\n\n## Agent entrypoints\n\n- https://read.significanthobbies.com/llms.txt\n- https://read.significanthobbies.com/api/ai\n- https://read.significanthobbies.com/index.md\n\n## Product links\n\n- Home: https://read.significanthobbies.com/ — App (auth for library)\n- Login: https://read.significanthobbies.com/login — Sign in\n\n## Machine surfaces\n\n- https://read.significanthobbies.com/llms.txt\n- https://read.significanthobbies.com/llms-full.txt\n- https://read.significanthobbies.com/api/ai\n- https://read.significanthobbies.com/index.md\n- https://read.significanthobbies.com/sitemap.xml\n- https://read.significanthobbies.com/robots.txt\n\n## Contact / fleet\n\n- Fleet: https://sassmaker.com\n- Agent email for directory verification: sarthakagrawal@agentmail.to\n", - "llmsTxt": "# Reader\n\n> Research library: capture, annotate, and AI-chat over your reading — private by default.\n\n## Product\n\n- [Home](https://read.significanthobbies.com/): App (auth for library)\n- [Login](https://read.significanthobbies.com/login): Sign in\n\n## Machine surfaces\n\n- [Agent catalog](https://read.significanthobbies.com/api/ai): JSON inventory of public surfaces\n- [Homepage markdown](https://read.significanthobbies.com/index.md): Product brief without JS\n- [This index](https://read.significanthobbies.com/llms.txt)\n\n## Optional\n\n- [Foundry](https://sassmaker.com): Parent fleet showcase\n", + "llmsFullTxt": "# Reader — full agent brief\n\nResearch library: capture, annotate, and AI-chat over your reading — private by default.\n\n## Index\n\n# Reader\n\nResearch library for capture, annotation, and AI chat over your reading.\n\n## Privacy\n\nPersonal libraries require auth and are not agent-indexed. Public marketing surfaces only.\n\n## Agent entrypoints\n\n- https://read.significanthobbies.com/llms.txt\n- https://read.significanthobbies.com/api/ai\n- https://read.significanthobbies.com/index.md\n\n## Product links\n\n- Home: https://read.significanthobbies.com/ — App (auth for library)\n- FAQ: https://read.significanthobbies.com/faq — Frequently asked questions\n- Changelog: https://read.significanthobbies.com/changelog — Verified product history\n- Login: https://read.significanthobbies.com/login — Sign in\n\n## Machine surfaces\n\n- https://read.significanthobbies.com/llms.txt\n- https://read.significanthobbies.com/llms-full.txt\n- https://read.significanthobbies.com/api/ai\n- https://read.significanthobbies.com/index.md\n- https://read.significanthobbies.com/sitemap.xml\n- https://read.significanthobbies.com/robots.txt\n\n## Contact / fleet\n\n- Fleet: https://sassmaker.com\n- Agent email for directory verification: sarthakagrawal@agentmail.to\n", + "llmsTxt": "# Reader\n\n> Research library: capture, annotate, and AI-chat over your reading — private by default.\n\n## Product\n\n- [Home](https://read.significanthobbies.com/): App (auth for library)\n- [FAQ](https://read.significanthobbies.com/faq): Frequently asked questions\n- [Changelog](https://read.significanthobbies.com/changelog): Verified product history\n- [Login](https://read.significanthobbies.com/login): Sign in\n\n## Machine surfaces\n\n- [Agent catalog](https://read.significanthobbies.com/api/ai): JSON inventory of public surfaces\n- [Homepage markdown](https://read.significanthobbies.com/index.md): Product brief without JS\n- [Full agent brief](https://read.significanthobbies.com/llms-full.txt): Complete product and privacy context\n- [HTML sitemap](https://read.significanthobbies.com/sitemap.xml): Canonical public pages\n- [This index](https://read.significanthobbies.com/llms.txt)\n\n## Optional\n\n- [Foundry](https://sassmaker.com): Parent fleet showcase\n", "indexMd": "# Reader\n\nResearch library for capture, annotation, and AI chat over your reading.\n\n## Privacy\n\nPersonal libraries require auth and are not agent-indexed. Public marketing surfaces only.\n\n## Agent entrypoints\n\n- https://read.significanthobbies.com/llms.txt\n- https://read.significanthobbies.com/api/ai\n- https://read.significanthobbies.com/index.md\n", "catalog": { "name": "Reader", @@ -36,6 +36,20 @@ export const AGENT_SURFACE = { "kind": "spa", "description": "Product home" }, + { + "id": "faq", + "url": "https://read.significanthobbies.com/faq", + "md": "https://read.significanthobbies.com/faq.md", + "kind": "static", + "description": "Frequently asked questions" + }, + { + "id": "changelog", + "url": "https://read.significanthobbies.com/changelog", + "md": "https://read.significanthobbies.com/changelog.md", + "kind": "static", + "description": "Verified product history" + }, { "id": "login", "url": "https://read.significanthobbies.com/login", diff --git a/src/agent-surfaces.test.ts b/src/agent-surfaces.test.ts new file mode 100644 index 0000000..1e7d166 --- /dev/null +++ b/src/agent-surfaces.test.ts @@ -0,0 +1,70 @@ +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { describe, expect, it } from 'vitest'; +import { AGENT_SURFACE } from './agent-edge.mjs'; + +const readPublic = (path: string) => readFileSync(resolve(process.cwd(), 'public', path), 'utf8'); + +function sitemapUrls(): string[] { + return [...readPublic('sitemap.xml').matchAll(/([^<]+)<\/loc>/g)].map( + (match) => match[1] ?? '' + ); +} + +describe('public agent surface parity', () => { + it('keeps the sitemap limited to canonical HTML surfaces', () => { + const catalogUrls = AGENT_SURFACE.catalog.surfaces.map((surface) => surface.url); + const urls = sitemapUrls(); + + expect(urls).toEqual(catalogUrls); + expect(urls).toHaveLength(4); + for (const url of urls) { + const path = new URL(url).pathname; + expect(path).not.toMatch(/\.(?:json|md|txt|xml)$/); + expect(path).not.toMatch(/^\/api(?:\/|$)/); + } + }); + + it('provides a substantive Markdown counterpart for every HTML surface', () => { + const publicOrigin = new URL(AGENT_SURFACE.url).origin; + + for (const surface of AGENT_SURFACE.catalog.surfaces) { + expect(surface.md).toBeTruthy(); + const markdownUrl = new URL(surface.md ?? ''); + expect(markdownUrl.origin).toBe(publicOrigin); + const markdown = readPublic(markdownUrl.pathname.replace(/^\//, '')); + expect(markdown).toMatch(/^#\s+\S/m); + expect(markdown.trim().length).toBeGreaterThan(120); + } + }); + + it('keeps machine resources discoverable but outside the HTML sitemap', () => { + const urls = new Set(sitemapUrls()); + const robots = readPublic('robots.txt'); + const llms = readPublic('llms.txt'); + const catalog = AGENT_SURFACE.catalog; + const machineResources = [ + catalog.llms, + catalog.llmsFull, + catalog.sitemap, + catalog.robots, + `${AGENT_SURFACE.url}/api/ai`, + `${AGENT_SURFACE.url}/index.md`, + ]; + + for (const resource of machineResources) { + expect(urls).not.toContain(resource); + } + expect(robots).toContain(`Sitemap: ${catalog.sitemap}`); + expect(robots).toContain('Allow: /llms.txt'); + expect(robots).toContain('Allow: /llms-full.txt'); + expect(robots).toContain('Allow: /index.md'); + expect(robots).toContain('Allow: /api/ai'); + expect(llms).toContain(catalog.sitemap); + expect(llms).toContain(catalog.llmsFull); + expect(llms).toContain('/api/ai'); + expect(AGENT_SURFACE.llmsTxt).toBe(llms); + expect(AGENT_SURFACE.llmsFullTxt).toBe(readPublic('llms-full.txt')); + expect(AGENT_SURFACE.catalog.surfaces).toEqual(JSON.parse(readPublic('api-ai.json')).surfaces); + }); +});