Use the unsubscribe link from your email to unsubscribe.
+ )}
+
+ );
+}
+```
+
+**File:** `src/App.tsx`Add unsubscribe route:
+
+```typescript
+// Add route
+} />
+```
+
+
+
+### Step 9: Integration Points
+
+**File:** `src/pages/Home.tsx`Add newsletter signup above footer:
+
+```typescript
+// Before footer section
+{siteConfig.newsletter.enabled &&
+ siteConfig.newsletter.signup.home.enabled &&
+ siteConfig.newsletter.signup.home.position === "above-footer" && (
+
+ )}
+
+{/* Footer section */}
+
+ {/* ... existing footer ... */}
+
+```
+
+**File:** `src/pages/Post.tsx`Add newsletter signup below post content (only for posts, not pages):
+
+```typescript
+// After BlogPost content, before footer
+{post && // Only for posts, not pages
+ siteConfig.newsletter.enabled &&
+ siteConfig.newsletter.signup.posts.enabled && (
+
+ )}
+
+
+```
+
+
+
+### Step 10: Webhook Handler (Future Email-to-Post)
+
+**File:** `convex/webhooks.ts`Create webhook handler for AgentMail events:
+
+```typescript
+import { httpAction } from "./_generated/server";
+import { internal } from "./_generated/api";
+
+export const agentmailWebhook = httpAction(async (ctx, request) => {
+ // Verify webhook signature from AgentMail
+ const signature = request.headers.get("x-agentmail-signature");
+ // Add signature verification logic here
+
+ const body = await request.json();
+
+ // Handle different event types
+ if (body.type === "message.received") {
+ // Process incoming email for email-to-post workflow
+ await ctx.runMutation(internal.newsletter.handleIncomingEmail, {
+ from: body.from,
+ subject: body.subject,
+ content: body.content,
+ attachments: body.attachments || [],
+ inboxId: body.inbox_id,
+ });
+ }
+
+ return new Response(JSON.stringify({ received: true }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+});
+```
+
+**File:** `convex/newsletter.ts`Add handler for incoming emails:
+
+```typescript
+// Handle incoming email (for email-to-post workflow)
+export const handleIncomingEmail = internalMutation({
+ args: {
+ from: v.string(),
+ subject: v.string(),
+ content: v.string(),
+ attachments: v.array(v.string()),
+ inboxId: v.string(),
+ },
+ returns: v.id("emailDrafts"),
+ handler: async (ctx, args) => {
+ // Parse subject for tags like [draft] or [publish]
+ const subjectLower = args.subject.toLowerCase();
+ const isDraft = subjectLower.includes("[draft]");
+ const isPublish = subjectLower.includes("[publish]");
+
+ const status = isPublish ? "published" : isDraft ? "draft" : "draft";
+
+ // Create draft post
+ return await ctx.db.insert("emailDrafts", {
+ from: args.from,
+ subject: args.subject,
+ content: args.content, // Markdown content
+ attachments: args.attachments,
+ status,
+ createdAt: Date.now(),
+ });
+ },
+});
+```
+
+**File:** `convex/http.ts`Add webhook route:
+
+```typescript
+import { agentmailWebhook } from "./webhooks";
+
+// Add route
+http.route({
+ path: "/webhooks/agentmail",
+ method: "POST",
+ handler: agentmailWebhook,
+});
+```
+
+
+
+### Step 11: Package.json and Environment Variables
+
+**File:** `package.json`Add newsletter scripts:
+
+```json
+{
+ "scripts": {
+ "newsletter:send": "npx tsx scripts/send-newsletter.ts",
+ "sync": "npx tsx scripts/sync-posts.ts"
+ }
+}
+```
+
+**File:** `.env.local.example`Add AgentMail environment variables:
+
+```bash
+# AgentMail Configuration (optional)
+AGENTMAIL_API_KEY=your_api_key_here
+AGENTMAIL_INBOX_USERNAME=newsletter
+AGENTMAIL_INBOX_DOMAIN=agentmail.to
+AGENTMAIL_AUTO_SEND=false
+AGENTMAIL_FROM_EMAIL=newsletter@agentmail.to
+UNSUBSCRIBE_SECRET=change-this-in-production
+```
+
+
+
+### Step 12: CSS Styling
+
+**File:** `src/styles/global.css`Add newsletter component styles matching existing theme:
+
+```css
+/* Newsletter Signup Component */
+.newsletter-signup {
+ margin: 2rem 0;
+ padding: 1.5rem;
+ border: 1px solid var(--border-color);
+ border-radius: 8px;
+ background: var(--bg-secondary);
+}
+
+.newsletter-signup__title {
+ font-size: var(--font-size-xl);
+ margin-bottom: 0.5rem;
+ color: var(--text-primary);
+}
+
+.newsletter-signup__description {
+ font-size: var(--font-size-base);
+ color: var(--text-secondary);
+ margin-bottom: 1rem;
+}
+
+.newsletter-signup__form {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.newsletter-signup__input {
+ padding: 0.75rem;
+ font-size: var(--font-size-base);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+}
+
+.newsletter-signup__button {
+ padding: 0.75rem 1.5rem;
+ font-size: var(--font-size-md);
+ background: var(--accent-color);
+ color: var(--text-on-accent);
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: opacity 0.2s;
+}
+
+.newsletter-signup__button:hover:not(:disabled) {
+ opacity: 0.9;
+}
+
+.newsletter-signup__button:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+.newsletter-signup__success {
+ padding: 0.75rem;
+ background: var(--success-bg, #d4edda);
+ color: var(--success-text, #155724);
+ border-radius: 4px;
+}
+
+.newsletter-signup__error {
+ color: var(--error-color, #dc3545);
+ font-size: var(--font-size-sm);
+ margin-top: 0.5rem;
+}
+
+/* Unsubscribe Page */
+.unsubscribe-page {
+ max-width: 600px;
+ margin: 2rem auto;
+ padding: 2rem;
+}
+
+.unsubscribe-page h1 {
+ font-size: var(--font-size-3xl);
+ margin-bottom: 1rem;
+}
+```
+
+
+
+### Step 13: Fork Configuration
+
+**File:** `fork-config.json.example`Add newsletter configuration:
+
+```json
+{
+ "newsletter": {
+ "enabled": false,
+ "agentmail": {
+ "inboxUsername": "newsletter",
+ "inboxDomain": "agentmail.to"
+ },
+ "signup": {
+ "requireName": false,
+ "showNameOptional": true,
+ "home": {
+ "enabled": false,
+ "position": "above-footer",
+ "title": "Stay Updated",
+ "description": "Get new posts delivered to your inbox"
+ },
+ "posts": {
+ "enabled": false,
+ "position": "below-content",
+ "title": "Enjoyed this post?",
+ "description": "Subscribe for more updates"
+ },
+ "page": {
+ "enabled": false,
+ "slug": "newsletter",
+ "title": "Newsletter",
+ "description": "Subscribe to get updates"
+ }
+ },
+ "notifications": {
+ "autoSendNewPosts": false,
+ "sendOnSync": false,
+ "fromName": "Your Site Name",
+ "fromEmail": "newsletter@agentmail.to"
+ }
+ }
+}
+```
+
+**File:** `FORK_CONFIG.md`Add newsletter configuration section:
+
+```markdown
+## Newsletter Configuration
+
+The newsletter feature is optional and disabled by default. To enable:
+
+1. Set `newsletter.enabled: true` in `siteConfig.ts`
+2. Add `AGENTMAIL_API_KEY` to `.env.local`
+3. Configure signup forms in `siteConfig.newsletter.signup`
+4. Optionally enable auto-send for new posts
+
+See `prds/agentmailplan-v1.md` for full documentation.
+```
+
+
+
+## Future Features (Not in Initial Implementation)
+
+These features are planned but not included in steps 1-11:
+
+- Weekly/monthly digest emails (cron jobs)
+- Developer notifications (stats summaries, new subscriber alerts)
+- Contact form via AgentMail
+- Email-to-post workflow (webhook handler created, but full workflow deferred)
+- Email replies/comments
+- RSS feed validation alerts
+
+These can be added incrementally after the core newsletter functionality is working.
+
+## Testing Checklist
+
+- [ ] Newsletter signup form appears on home page (above footer) when enabled
+- [ ] Newsletter signup form appears on blog posts (below content) when enabled
+- [ ] Newsletter signup form appears on dedicated newsletter page
+- [ ] Name field shows/hides based on configuration
+- [ ] Subscription saves to Convex database
+- [ ] Unsubscribe link works with token verification
+- [ ] `npm run newsletter:send -- ` sends email to all subscribers
+- [ ] Auto-send works during `npm run sync` if enabled
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
index fd4a73a..e104514 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,7 +4,7 @@ Instructions for AI coding agents working on this codebase.
## Project overview
-An open-source publishing framework for AI agents and developers. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
+Your content is instantly available to browsers, LLMs, and AI agents.. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
**Key features:**
- Markdown posts with frontmatter
@@ -14,6 +14,16 @@ An open-source publishing framework for AI agents and developers. Write markdown
- RSS feeds and sitemap for SEO
- API endpoints for AI/LLM access
+## Current Status
+
+- **Site Name**: markdown
+- **Site Title**: markdown sync framework
+- **Site URL**: https://markdown.fast
+- **Total Posts**: 11
+- **Total Pages**: 4
+- **Latest Post**: 2025-12-21
+- **Last Updated**: 2025-12-25T06:55:43.145Z
+
## Tech stack
| Layer | Technology |
diff --git a/FORK_CONFIG.md b/FORK_CONFIG.md
index c5cf17a..9690287 100644
--- a/FORK_CONFIG.md
+++ b/FORK_CONFIG.md
@@ -78,7 +78,7 @@ Edit each file individually following the guide below.
| File | What to Update |
| ----------------------------------- | -------------------------------------------- |
-| `src/config/siteConfig.ts` | Site name, bio, GitHub username, features |
+| `src/config/siteConfig.ts` | Site name, bio, GitHub username, gitHubRepo config, features |
| `src/pages/Home.tsx` | Intro paragraph, footer links |
| `src/pages/Post.tsx` | `SITE_URL`, `SITE_NAME` constants |
| `convex/http.ts` | `SITE_URL`, `SITE_NAME` constants |
@@ -158,6 +158,15 @@ export const siteConfig: SiteConfig = {
convex: "https://convex.dev",
netlify: "https://netlify.com",
},
+
+ // GitHub repository config (for AI service links)
+ // Used by ChatGPT, Claude, Perplexity "Open in AI" buttons
+ gitHubRepo: {
+ owner: "YOURUSERNAME", // GitHub username or organization
+ repo: "YOUR-REPO-NAME", // Repository name
+ branch: "main", // Default branch
+ contentPath: "public/raw", // Path to raw markdown files
+ },
};
```
@@ -412,8 +421,14 @@ Creator Info:
- LinkedIn: https://www.linkedin.com/in/[YOURPROFILE]/
- GitHub: https://github.com/[YOURUSERNAME]
+GitHub Repo Config (for AI service links):
+- Owner: [YOURUSERNAME]
+- Repo: [YOUR-REPO]
+- Branch: main
+- Content Path: public/raw
+
Update these files:
-1. src/config/siteConfig.ts - site name, bio, GitHub username
+1. src/config/siteConfig.ts - site name, bio, GitHub username, gitHubRepo config
2. src/pages/Home.tsx - intro paragraph and footer section with all creator links
3. src/pages/Post.tsx - SITE_URL and SITE_NAME constants
4. convex/http.ts - SITE_URL and SITE_NAME constants
@@ -436,6 +451,36 @@ Update these files:
---
+## Syncing Discovery Files
+
+Discovery files (`AGENTS.md` and `public/llms.txt`) can be automatically updated with your current app data.
+
+### Commands
+
+| Command | Description |
+| ------- | ----------- |
+| `npm run sync:discovery` | Update discovery files with local Convex data |
+| `npm run sync:discovery:prod` | Update discovery files with production Convex data |
+| `npm run sync:all` | Sync content + discovery files together (development) |
+| `npm run sync:all:prod` | Sync content + discovery files together (production) |
+
+### When to run
+
+- **`npm run sync`**: Run when you add, edit, or remove markdown content
+- **`npm run sync:discovery`**: Run when you change site configuration or want to update discovery files with latest post counts
+- **`npm run sync:all`**: Run both syncs together (recommended for complete updates)
+
+### What gets updated
+
+| File | Updated Content |
+| ---- | --------------- |
+| `AGENTS.md` | Project overview, current status (site name, URL, post/page counts) |
+| `public/llms.txt` | Site info, total posts, latest post date, GitHub URL |
+
+The script reads from `siteConfig.ts` and queries Convex for live content statistics.
+
+---
+
## Optional: Content Files
Replace example content in:
diff --git a/README.md b/README.md
index 8b98a4e..c61be65 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,20 @@ Write markdown locally, run `npm run sync` (dev) or `npm run sync:prod` (product
**How publishing works:** Write posts in markdown, run `npm run sync` for development or `npm run sync:prod` for production, and they appear on your live site immediately. No rebuild or redeploy needed. Convex handles real-time data sync, so all connected browsers update automatically.
+**Sync commands:**
+
+**Development:**
+
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
**How versioning works:** Markdown files live in `content/blog/` and `content/pages/`. These are regular files in your git repo. Commit changes, review diffs, roll back like any codebase. The sync command pushes content to Convex.
```bash
@@ -212,10 +226,17 @@ Both files are gitignored. Each developer creates their own.
### Sync Commands
-| Command | Target | When to use |
-| ------------------- | ----------- | --------------------------- |
-| `npm run sync` | Development | Local testing, new posts |
-| `npm run sync:prod` | Production | Deploy content to live site |
+**Development:**
+
+- `npm run sync` - Sync markdown content to development Convex
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt) with development data
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+
+- `npm run sync:prod` - Sync markdown content to production Convex
+- `npm run sync:discovery:prod` - Update discovery files with production data
+- `npm run sync:all:prod` - Sync content + discovery files together
**Development sync:**
@@ -295,16 +316,20 @@ markdown-site/
## Scripts Reference
-| Script | Description |
-| --------------------- | ---------------------------------------------- |
-| `npm run dev` | Start Vite dev server |
-| `npm run dev:convex` | Start Convex dev backend |
-| `npm run sync` | Sync posts to dev deployment |
-| `npm run sync:prod` | Sync posts to production deployment |
-| `npm run import` | Import URL as local markdown draft (then sync) |
-| `npm run build` | Build for production |
-| `npm run deploy` | Sync + build (for manual deploys) |
-| `npm run deploy:prod` | Deploy Convex functions + sync to production |
+| Script | Description |
+| ----------------------------- | ---------------------------------------------- |
+| `npm run dev` | Start Vite dev server |
+| `npm run dev:convex` | Start Convex dev backend |
+| `npm run sync` | Sync posts to dev deployment |
+| `npm run sync:prod` | Sync posts to production deployment |
+| `npm run sync:discovery` | Update discovery files (development) |
+| `npm run sync:discovery:prod` | Update discovery files (production) |
+| `npm run sync:all` | Sync content + discovery (development) |
+| `npm run sync:all:prod` | Sync content + discovery (production) |
+| `npm run import` | Import URL as local markdown draft (then sync) |
+| `npm run build` | Build for production |
+| `npm run deploy` | Sync + build (for manual deploys) |
+| `npm run deploy:prod` | Deploy Convex functions + sync to production |
## Tech Stack
@@ -396,6 +421,7 @@ FIRECRAWL_API_KEY=fc-your-api-key
- `npm run sync` for development
- `npm run sync:prod` for production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
Imported posts are created as drafts (`published: false`). Review, edit, set `published: true`, then sync.
diff --git a/TASK.md b/TASK.md
index 2c70175..bb4fa8b 100644
--- a/TASK.md
+++ b/TASK.md
@@ -8,10 +8,17 @@
## Current Status
-v1.27.0 ready. Added homepage post limit and optional "read more" link configuration.
+v1.28.0 ready. Added discovery files sync automation with new sync commands.
## Completed
+- [x] Discovery files sync script (sync-discovery-files.ts)
+- [x] Automated updates for AGENTS.md and llms.txt with current app data
+- [x] New npm scripts: sync:discovery, sync:discovery:prod, sync:all, sync:all:prod
+- [x] Fork configuration updated to support gitHubRepo config
+- [x] Backward compatibility for legacy githubUsername/githubRepo fields
+- [x] Documentation updated across all files with new sync commands
+
- [x] Homepage post limit configuration (homePostsLimit in siteConfig.postsDisplay)
- [x] Optional "read more" link below limited post list (homePostsReadMore config)
- [x] Customizable link text and destination URL
diff --git a/changelog.md b/changelog.md
index aea8e49..06c37fe 100644
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,41 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [1.28.0] - 2025-12-25
+
+### Added
+
+- Discovery files sync script
+ - New `sync-discovery-files.ts` script that updates AGENTS.md and llms.txt with current app data
+ - Reads from siteConfig.ts and queries Convex for post/page counts and latest post date
+ - Preserves existing AGENTS.md instructional content while updating dynamic sections
+ - Regenerates llms.txt with current site information and GitHub URLs
+- New npm sync commands
+ - `npm run sync:discovery` - Update discovery files (development)
+ - `npm run sync:discovery:prod` - Update discovery files (production)
+ - `npm run sync:all` - Sync content + discovery files together (development)
+ - `npm run sync:all:prod` - Sync content + discovery files together (production)
+- Fork configuration support for gitHubRepo
+ - Added `gitHubRepoConfig` to fork-config.json.example
+ - Updated configure-fork.ts to handle gitHubRepo with backward compatibility
+ - Legacy githubUsername/githubRepo fields still work
+
+### Changed
+
+- `fork-config.json.example`: Added gitHubRepoConfig object with owner, repo, branch, contentPath
+- `scripts/configure-fork.ts`: Added gitHubRepo update logic with legacy field fallback
+- `FORK_CONFIG.md`: Added gitHubRepo documentation and sync:discovery command reference
+- `files.md`: Added sync-discovery-files.ts entry and sync commands documentation
+- Documentation updated across all files with new sync commands
+
+### Technical
+
+- New script: `scripts/sync-discovery-files.ts`
+- Uses ConvexHttpClient to query live data from Convex
+- Regex-based siteConfig.ts parsing for gitHubRepo extraction
+- Selective AGENTS.md updates preserve instructional content
+- Error handling with graceful fallbacks for missing data
+
## [1.27.0] - 2025-12-24
### Added
diff --git a/content/blog/about-this-blog.md b/content/blog/about-this-blog.md
index 41865b9..1f3ae01 100644
--- a/content/blog/about-this-blog.md
+++ b/content/blog/about-this-blog.md
@@ -82,6 +82,18 @@ The setup takes about 10 minutes:
**Development vs Production:** Use `npm run sync` when testing locally against your dev Convex deployment. Use `npm run sync:prod` when deploying content to your live production site.
+**Sync commands:**
+
+**Development:**
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
**Import external content:** Run `npm run import ` to scrape and create local markdown drafts. Then sync to dev or prod. There is no separate import command for production because import creates local files only.
Read the [setup guide](/setup-guide) for detailed steps.
diff --git a/content/blog/happy-holidays-2025.md b/content/blog/happy-holidays-2025.md
new file mode 100644
index 0000000..21aa54e
--- /dev/null
+++ b/content/blog/happy-holidays-2025.md
@@ -0,0 +1,34 @@
+---
+title: "Happy holidays and thank you"
+description: "A quick note of thanks for stars, forks, and feedback. More AI-first publishing features coming in 2026."
+date: "2025-12-25"
+slug: "happy-holidays-2025"
+published: true
+tags: ["updates", "community", "ai"]
+readTime: "2 min read"
+featured: true
+featuredOrder: 0
+excerpt: "Thank you for the stars, forks, and feedback. More AI-first publishing features are coming."
+authorName: "Wayne Sutton"
+authorImage: "/images/authors/markdown.png"
+---
+
+# Happy holidays and thank you
+
+Thank you for using this markdown framework. Your stars, forks, and feedback help make it better.
+
+## Feedback and feature requests
+
+Found a bug? Have an idea? Open an issue on [GitHub](https://github.com/waynesutton/markdown-site). Issues help prioritize what to build next.
+
+## What's coming
+
+More AI-first publishing features are on the way. The changelog at [/changelog](/changelog) tracks all updates. Check it regularly for new releases.
+
+Recent additions include tag pages, related posts, and improved AI service integrations. The roadmap focuses on making content creation faster and more accessible to AI agents.
+
+## Keep building
+
+Write markdown. Sync from the terminal. Your content appears instantly. That's the goal.
+
+Happy holidays.
diff --git a/content/blog/setup-guide.md b/content/blog/setup-guide.md
index 8fd1f5a..bf94096 100644
--- a/content/blog/setup-guide.md
+++ b/content/blog/setup-guide.md
@@ -186,8 +186,18 @@ export default defineSchema({
Blog posts live in `content/blog/` as markdown files. Sync them to Convex:
+**Development:**
```bash
-npm run sync
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files (AGENTS.md, llms.txt)
+npm run sync:all # Sync content + discovery files together
+```
+
+**Production:**
+```bash
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync content + discovery files together
```
This reads all markdown files, parses the frontmatter, and uploads them to your Convex database.
@@ -391,16 +401,17 @@ This image appears when sharing on social media. Recommended: 1200x630 pixels.
2. Push to GitHub
3. Wait for Netlify to rebuild
-The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
+The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site. Use `npm run sync:discovery` to update discovery files (AGENTS.md, llms.txt) when site configuration changes.
### Sync After Adding Posts
After adding or editing posts, sync to Convex.
**Development sync:**
-
```bash
-npm run sync
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files
+npm run sync:all # Sync everything together
```
**Production sync:**
@@ -414,9 +425,10 @@ VITE_CONVEX_URL=https://your-prod-deployment.convex.cloud
Get your production URL from the [Convex Dashboard](https://dashboard.convex.dev) by selecting your project and switching to the Production deployment.
Then sync:
-
```bash
-npm run sync:prod
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync everything together
```
### Environment Files
@@ -435,6 +447,7 @@ Both files are gitignored. Each developer creates their own local environment fi
| Blog posts in `content/blog/` | `npm run sync` | Instant (no rebuild) |
| Pages in `content/pages/` | `npm run sync` | Instant (no rebuild) |
| Featured items (via frontmatter) | `npm run sync` | Instant (no rebuild) |
+| Site config changes | `npm run sync:discovery` | Updates discovery files |
| Import external URL | `npm run import` then sync | Instant (no rebuild) |
| Images in `public/images/` | Git commit + push | Requires rebuild |
| `siteConfig` in `Home.tsx` | Redeploy | Requires rebuild |
@@ -1080,8 +1093,9 @@ Each post and page includes a share dropdown with options for AI tools:
| What you want | Command needed |
| ------------------------------------ | ------------------------------ |
| Content visible on your site | `npm run sync` or `sync:prod` |
+| Discovery files updated | `npm run sync:discovery` or `sync:discovery:prod` |
| AI links (ChatGPT/Claude/Perplexity) | `git push` to GitHub |
-| Both | `npm run sync` then `git push` |
+| Both content and discovery | `npm run sync:all` or `sync:all:prod` |
**Download as SKILL.md** formats the content as an Anthropic Agent Skills file with metadata, triggers, and instructions sections.
@@ -1131,6 +1145,7 @@ The import script will:
- Run `npm run sync` to push to development
- Run `npm run sync:prod` to push to production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
Imported posts are created as drafts (`published: false`). Review, edit, set `published: true`, then sync to your target environment.
@@ -1141,7 +1156,8 @@ Imported posts are created as drafts (`published: false`). Review, edit, set `pu
1. Check that `published: true` in frontmatter
2. Run `npm run sync` to sync posts to development
3. Run `npm run sync:prod` to sync posts to production
-4. Verify posts exist in Convex dashboard
+4. Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
+5. Verify posts exist in Convex dashboard
### RSS/Sitemap not working
diff --git a/content/pages/about.md b/content/pages/about.md
index 7805284..c1b7dd2 100644
--- a/content/pages/about.md
+++ b/content/pages/about.md
@@ -14,6 +14,18 @@ An open-source publishing framework for AI agents and developers. Write markdown
**CLI publishing workflow.** Write markdown locally, then run `npm run sync` (dev) or `npm run sync:prod` (production). Content appears instantly via Convex real-time sync. Images require git commit and push since they are served as static files from Netlify.
+**Sync commands:**
+
+**Development:**
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
**Version controlled.** Markdown source files live in your repo alongside code. Commit changes, review diffs, roll back like any codebase. The sync command pushes content to the database.
```bash
diff --git a/content/pages/changelog-page.md b/content/pages/changelog-page.md
index 917b87f..8498354 100644
--- a/content/pages/changelog-page.md
+++ b/content/pages/changelog-page.md
@@ -8,6 +8,30 @@ layout: "sidebar"
All notable changes to this project.
+## v1.28.0
+
+Released December 25, 2025
+
+**Discovery files sync automation**
+
+- New discovery files sync script
+ - Automatically updates AGENTS.md and llms.txt with current app data
+ - Reads from siteConfig.ts and queries Convex for post/page counts
+ - Preserves existing AGENTS.md instructional content
+ - Regenerates llms.txt with current site information
+- New npm sync commands
+ - `npm run sync:discovery` - Update discovery files (development)
+ - `npm run sync:discovery:prod` - Update discovery files (production)
+ - `npm run sync:all` - Sync content + discovery files together (development)
+ - `npm run sync:all:prod` - Sync content + discovery files together (production)
+- Fork configuration support for gitHubRepo
+ - Added gitHubRepoConfig to fork-config.json.example
+ - Updated configure-fork.ts with backward compatibility for legacy fields
+
+Updated files: `scripts/sync-discovery-files.ts`, `package.json`, `fork-config.json.example`, `scripts/configure-fork.ts`, `FORK_CONFIG.md`, `files.md`
+
+Documentation updated: `README.md`, `docs.md`, `setup-guide.md`, `about.md`, `about-this-blog.md`
+
## v1.27.0
Released December 24, 2025
diff --git a/content/pages/docs.md b/content/pages/docs.md
index b3c9f27..8ed9869 100644
--- a/content/pages/docs.md
+++ b/content/pages/docs.md
@@ -10,6 +10,20 @@ Reference documentation for setting up, customizing, and deploying this markdown
**How publishing works:** Write posts in markdown, run `npm run sync` for development or `npm run sync:prod` for production, and they appear on your live site immediately. No rebuild or redeploy needed. Convex handles real-time data sync, so connected browsers update automatically.
+**Sync commands:**
+
+**Development:**
+
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
## Quick start
```bash
@@ -214,26 +228,42 @@ To add a custom frontmatter field, update these files:
### Syncing content
-```bash
-# Development
-npm run sync
+**Development:**
-# Production
-npm run sync:prod
+```bash
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files (AGENTS.md, llms.txt)
+npm run sync:all # Sync content + discovery files together
+```
+
+**Production:**
+
+```bash
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync content + discovery files together
+```
+
+**Sync everything together:**
+
+```bash
+npm run sync:all # Development: content + discovery
+npm run sync:all:prod # Production: content + discovery
```
### When to sync vs deploy
-| What you're changing | Command | Timing |
-| -------------------------------- | -------------------------- | -------------------- |
-| Blog posts in `content/blog/` | `npm run sync` | Instant (no rebuild) |
-| Pages in `content/pages/` | `npm run sync` | Instant (no rebuild) |
-| Featured items (via frontmatter) | `npm run sync` | Instant (no rebuild) |
-| Import external URL | `npm run import` then sync | Instant (no rebuild) |
-| Images in `public/images/` | Git commit + push | Requires rebuild |
-| `siteConfig` in `Home.tsx` | Redeploy | Requires rebuild |
-| Logo gallery config | Redeploy | Requires rebuild |
-| React components/styles | Redeploy | Requires rebuild |
+| What you're changing | Command | Timing |
+| -------------------------------- | -------------------------- | ----------------------- |
+| Blog posts in `content/blog/` | `npm run sync` | Instant (no rebuild) |
+| Pages in `content/pages/` | `npm run sync` | Instant (no rebuild) |
+| Featured items (via frontmatter) | `npm run sync` | Instant (no rebuild) |
+| Site config changes | `npm run sync:discovery` | Updates discovery files |
+| Import external URL | `npm run import` then sync | Instant (no rebuild) |
+| Images in `public/images/` | Git commit + push | Requires rebuild |
+| `siteConfig` in `Home.tsx` | Redeploy | Requires rebuild |
+| Logo gallery config | Redeploy | Requires rebuild |
+| React components/styles | Redeploy | Requires rebuild |
**Markdown content** syncs instantly to Convex. **Images and source code** require pushing to GitHub for Netlify to rebuild.
@@ -408,7 +438,7 @@ excerpt: "Short description for card view."
image: "/images/thumbnail.png"
```
-Then run `npm run sync`. No redeploy needed.
+Then run `npm run sync` or `npm run sync:all`. No redeploy needed.
| Field | Description |
| --------------- | -------------------------------------------- |
@@ -641,7 +671,7 @@ Mobile sizes defined in `@media (max-width: 768px)` block.
2. Push to GitHub
3. Wait for Netlify to rebuild
-The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
+The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site. Use `npm run sync:discovery` to update discovery files (AGENTS.md, llms.txt) when site configuration changes.
**Logo options:**
@@ -689,11 +719,12 @@ Each post and page includes a share dropdown with options:
**Git push required for AI links:** The "Open in ChatGPT," "Open in Claude," and "Open in Perplexity" options use GitHub raw URLs. For these to work, you must push your content to GitHub with `git push`. The `npm run sync` command syncs content to Convex for your live site, but AI services fetch directly from GitHub.
-| What you want | Command needed |
-| ------------------------------------ | ------------------------------ |
-| Content visible on your site | `npm run sync` or `sync:prod` |
-| AI links (ChatGPT/Claude/Perplexity) | `git push` to GitHub |
-| Both | `npm run sync` then `git push` |
+| What you want | Command needed |
+| ------------------------------------ | ------------------------------------------------- |
+| Content visible on your site | `npm run sync` or `sync:prod` |
+| Discovery files updated | `npm run sync:discovery` or `sync:discovery:prod` |
+| AI links (ChatGPT/Claude/Perplexity) | `git push` to GitHub |
+| Both content and discovery | `npm run sync:all` or `sync:all:prod` |
**Download as SKILL.md:** Downloads the content formatted as an Anthropic Agent Skills file with metadata, triggers, and instructions sections.
@@ -727,7 +758,7 @@ All stats update automatically via Convex subscriptions.
## Raw markdown files
-When you run `npm run sync` (development) or `npm run sync:prod` (production), static `.md` files are generated in `public/raw/` for each published post and page.
+When you run `npm run sync` (development) or `npm run sync:prod` (production), static `.md` files are generated in `public/raw/` for each published post and page. Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together.
**Access pattern:** `/raw/{slug}.md`
@@ -801,6 +832,7 @@ The import command creates local markdown files only. It does not interact with
- `npm run sync` to push to development
- `npm run sync:prod` to push to production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
There is no `npm run import:prod` because import creates local files and sync handles the target environment.
@@ -882,6 +914,7 @@ export default defineSchema({
- Check `published: true` in frontmatter
- Run `npm run sync` for development
- Run `npm run sync:prod` for production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
- Verify in Convex dashboard
**RSS/Sitemap errors**
diff --git a/files.md b/files.md
index 674f506..304a0ec 100644
--- a/files.md
+++ b/files.md
@@ -159,11 +159,26 @@ Markdown files for static pages like About, Projects, Contact, Changelog.
## Scripts (`scripts/`)
-| File | Description |
-| -------------------- | ---------------------------------------------------------- |
-| `sync-posts.ts` | Syncs markdown files to Convex at build time |
-| `import-url.ts` | Imports external URLs as markdown posts (Firecrawl) |
-| `configure-fork.ts` | Automated fork configuration (reads fork-config.json) |
+| File | Description |
+| -------------------------- | ---------------------------------------------------------- |
+| `sync-posts.ts` | Syncs markdown files to Convex at build time |
+| `sync-discovery-files.ts` | Updates AGENTS.md and llms.txt with current app data |
+| `import-url.ts` | Imports external URLs as markdown posts (Firecrawl) |
+| `configure-fork.ts` | Automated fork configuration (reads fork-config.json) |
+
+### Sync Commands
+
+**Development:**
+- `npm run sync` - Sync markdown content to development Convex
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt) with development data
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content to production Convex
+- `npm run sync:discovery:prod` - Update discovery files with production data
+
+**Sync everything together:**
+- `npm run sync:all` - Run both content sync and discovery sync (development)
+- `npm run sync:all:prod` - Run both content sync and discovery sync (production)
### Frontmatter Flow
@@ -202,7 +217,7 @@ Frontmatter is the YAML metadata at the top of each markdown file. Here is how i
### Raw Markdown Files (`public/raw/`)
-Static markdown files generated during `npm run sync`. Each published post and page gets a corresponding `.md` file for direct access by users, search engines, and AI agents.
+Static markdown files generated during `npm run sync` or `npm run sync:prod`. Each published post and page gets a corresponding `.md` file for direct access by users, search engines, and AI agents.
| File Pattern | Description |
| -------------- | ---------------------------------------------- |
diff --git a/fork-config.json.example b/fork-config.json.example
index 7031617..665d72e 100644
--- a/fork-config.json.example
+++ b/fork-config.json.example
@@ -14,6 +14,12 @@
"github": "https://github.com/yourusername"
},
"bio": "Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents.",
+ "gitHubRepoConfig": {
+ "owner": "yourusername",
+ "repo": "your-repo-name",
+ "branch": "main",
+ "contentPath": "public/raw"
+ },
"logoGallery": {
"enabled": true,
"title": "Built with",
diff --git a/package.json b/package.json
index 0b903de..221e7b7 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,10 @@
"preview": "vite preview",
"sync": "npx tsx scripts/sync-posts.ts",
"sync:prod": "SYNC_ENV=production npx tsx scripts/sync-posts.ts",
+ "sync:discovery": "npx tsx scripts/sync-discovery-files.ts",
+ "sync:discovery:prod": "SYNC_ENV=production npx tsx scripts/sync-discovery-files.ts",
+ "sync:all": "npm run sync && npm run sync:discovery",
+ "sync:all:prod": "npm run sync:prod && npm run sync:discovery:prod",
"import": "npx tsx scripts/import-url.ts",
"configure": "npx tsx scripts/configure-fork.ts",
"deploy": "npm run sync && npm run build",
diff --git a/prds/AgentMail-ideas.md b/prds/AgentMail-ideas.md
new file mode 100644
index 0000000..cb14723
--- /dev/null
+++ b/prds/AgentMail-ideas.md
@@ -0,0 +1,114 @@
+# AgentMail Integration Ideas for Markdown Blog
+
+Ideas for integrating [AgentMail](https://agentmail.to/) into the markdown blog application to enhance developer experience, user experience, and interactive features.
+
+## Developer Experience (Building)
+
+### 1. Email-to-Post Workflow
+
+- Developers email markdown content to a dedicated inbox
+- Agent automatically creates draft posts from email content
+- Handle attachments (images) - agent processes and uploads them
+- Use subject line tags like `[draft]` or `[publish]` for workflow control
+
+### 2. Content Curation Agent
+
+- Agent monitors RSS feeds or URLs and automatically creates post drafts
+- Email agent URLs to import as markdown posts
+- Email threads for review/approval workflows before publishing
+
+### 3. Newsletter Management
+
+- Automated weekly/monthly digest emails sent to subscribers
+- Agent compiles recent posts and formats email newsletters
+- Reply-to support for subscriber engagement
+
+### 4. Developer Notifications
+
+- Daily/weekly stats summaries via email
+- New subscriber alerts
+- Email replies/comments notifications
+- RSS feed validation alerts
+
+## User Experience (Reading)
+
+### 5. Email Subscriptions
+
+- Users subscribe to all posts or specific tags
+- Get new post notifications or digests
+- Include post excerpts with "read more" links
+
+### 6. Email Newsletter
+
+- Weekly/monthly digest of new posts
+- Group by tags or themes
+- Personalization based on reading history
+
+### 7. Reply via Email
+
+- Users reply to post notification emails to comment
+- Thread conversations via email
+- Agents parse and add replies to posts/pages
+
+## Interactive Features (Receiving)
+
+### 8. Email-Based Contact
+
+- Contact form sends via AgentMail
+- Agent categorizes inquiries (support, feedback, collaboration)
+- Auto-reply confirmations
+- Forward to appropriate team member
+
+### 9. Guest Post Submissions
+
+- Accept guest post submissions via email
+- Agent validates markdown format
+- Creates draft posts for review
+- Sends confirmation/rejection emails
+
+### 10. Feedback and Comments
+
+- Readers email feedback on posts
+- Agent extracts relevant quotes
+- Creates comment threads or feedback summaries
+- Send thank-you emails
+
+### 11. Content Requests
+
+- Email topics to request
+- Agent creates feature requests or drafts
+- Track requests in Convex table
+- Follow up on status
+
+## Advanced Integrations
+
+### 12. AI-Powered Content Assistant
+
+- Email content questions to agent
+- Agent searches your blog content
+- Replies with relevant excerpts and links
+- Uses semantic search on your posts
+
+### 13. Automated Outreach
+
+- Agent identifies external blogs for cross-posting
+- Sends personalized outreach emails
+- Tracks responses and follow-ups
+
+### 14. Community Engagement
+
+- Weekly community email with top posts, comments, discussions
+- Agent compiles engagement metrics
+- Personalizes based on subscriber preferences
+
+## Implementation Strategy
+
+**Start Simple:**
+
+1. Email subscriptions - readers subscribe, receive new post notifications
+2. Contact form - replace or augment current contact page
+3. Developer notifications - stats summaries and alerts
+
+**Then Expand:** 4. Email-to-post workflow - content creation via email 5. Newsletter automation - scheduled digests 6. Interactive features - email comments and feedback
+
+The key advantage of AgentMail is that agents can handle email interactions autonomously without OAuth/MFA hassles, so you can create truly autonomous workflows that integrate with your Convex backend.
diff --git a/public/llms.txt b/public/llms.txt
index df79417..369f2d9 100644
--- a/public/llms.txt
+++ b/public/llms.txt
@@ -1,13 +1,17 @@
# llms.txt - Information for AI assistants and LLMs
# Learn more: https://llmstxt.org/
+# Last updated: 2025-12-25T06:55:43.147Z
-> An open-source publishing framework for AI agents and developers. Write markdown, sync from the terminal.
+> Your content is instantly available to browsers, LLMs, and AI agents.
# Site Information
-- Name: markdown sync framework
+- Name: markdown
- URL: https://markdown.fast
-- Description: An open-source publishing framework for AI agents and developers. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
+- Description: Your content is instantly available to browsers, LLMs, and AI agents. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
- Topics: Markdown, Convex, React, TypeScript, Netlify, Open Source, AI, LLM, AEO, GEO
+- Total Posts: 11
+- Latest Post: 2025-12-21
+- GitHub: https://github.com/waynesutton/markdown-site
# API Endpoints
diff --git a/public/raw/about-this-blog.md b/public/raw/about-this-blog.md
index d9975f7..35fd43b 100644
--- a/public/raw/about-this-blog.md
+++ b/public/raw/about-this-blog.md
@@ -78,6 +78,18 @@ The setup takes about 10 minutes:
**Development vs Production:** Use `npm run sync` when testing locally against your dev Convex deployment. Use `npm run sync:prod` when deploying content to your live production site.
+**Sync commands:**
+
+**Development:**
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
**Import external content:** Run `npm run import ` to scrape and create local markdown drafts. Then sync to dev or prod. There is no separate import command for production because import creates local files only.
Read the [setup guide](/setup-guide) for detailed steps.
diff --git a/public/raw/about.md b/public/raw/about.md
index 40ff81e..4ff99d8 100644
--- a/public/raw/about.md
+++ b/public/raw/about.md
@@ -2,7 +2,7 @@
---
Type: page
-Date: 2025-12-24
+Date: 2025-12-25
---
An open-source publishing framework for AI agents and developers. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
@@ -13,6 +13,18 @@ An open-source publishing framework for AI agents and developers. Write markdown
**CLI publishing workflow.** Write markdown locally, then run `npm run sync` (dev) or `npm run sync:prod` (production). Content appears instantly via Convex real-time sync. Images require git commit and push since they are served as static files from Netlify.
+**Sync commands:**
+
+**Development:**
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
**Version controlled.** Markdown source files live in your repo alongside code. Commit changes, review diffs, roll back like any codebase. The sync command pushes content to the database.
```bash
diff --git a/public/raw/changelog.md b/public/raw/changelog.md
index f02a55d..6156177 100644
--- a/public/raw/changelog.md
+++ b/public/raw/changelog.md
@@ -2,11 +2,57 @@
---
Type: page
-Date: 2025-12-24
+Date: 2025-12-25
---
All notable changes to this project.
+## v1.27.0
+
+Released December 24, 2025
+
+**Homepage post limit and optional read more link**
+
+- Configurable post limit for homepage via `siteConfig.postsDisplay.homePostsLimit`
+ - Default limit set to 10 most recent posts
+ - Set to `undefined` to show all posts (no limit)
+- Optional "read more" link below limited post list
+ - Configurable via `siteConfig.postsDisplay.homePostsReadMore`
+ - Customizable link text and destination URL
+ - Only appears when posts are limited and there are more posts than the limit
+ - Default links to `/blog` page
+ - Can be disabled by setting `enabled: false`
+
+Updated files: `src/config/siteConfig.ts`, `src/pages/Home.tsx`, `src/styles/global.css`
+
+## v1.26.0
+
+Released December 24, 2025
+
+**Tag pages, related posts, and AI service links re-enabled**
+
+- Tag pages at `/tags/[tag]` route
+ - Dynamic tag archive pages showing all posts with a specific tag
+ - View mode toggle (list/cards) with localStorage persistence
+ - Mobile responsive layout matching existing blog page design
+ - Sitemap updated to include all tag pages dynamically
+- Related posts component for blog post footers
+ - Shows up to 3 related posts based on shared tags
+ - Sorted by relevance (number of shared tags) then by date
+ - Only displays on blog posts (not static pages)
+- Improved tag links in post footers
+ - Tags now link to `/tags/[tag]` archive pages
+ - Visual styling consistent with existing theme
+- Open in AI service links re-enabled in CopyPageDropdown
+ - Uses GitHub raw URLs instead of Netlify paths (bypasses edge function issues)
+ - ChatGPT, Claude, and Perplexity links with universal prompt
+ - "Requires git push" hint for users (npm sync alone doesn't update GitHub)
+ - Visual divider separating AI options from other menu items
+
+Updated files: `src/config/siteConfig.ts`, `convex/schema.ts`, `convex/posts.ts`, `convex/http.ts`, `src/pages/TagPage.tsx`, `src/pages/Post.tsx`, `src/components/CopyPageDropdown.tsx`, `src/styles/global.css`, `src/App.tsx`
+
+Documentation updated: `content/pages/docs.md`, `content/blog/setup-guide.md`
+
## v1.25.2
Released December 24, 2025
diff --git a/public/raw/contact.md b/public/raw/contact.md
index 9c73c33..d7a5199 100644
--- a/public/raw/contact.md
+++ b/public/raw/contact.md
@@ -2,7 +2,7 @@
---
Type: page
-Date: 2025-12-24
+Date: 2025-12-25
---
You found the contact page. Nice
diff --git a/public/raw/docs.md b/public/raw/docs.md
index 8ac53e2..caeb034 100644
--- a/public/raw/docs.md
+++ b/public/raw/docs.md
@@ -2,13 +2,25 @@
---
Type: page
-Date: 2025-12-24
+Date: 2025-12-25
---
Reference documentation for setting up, customizing, and deploying this markdown framework.
**How publishing works:** Write posts in markdown, run `npm run sync` for development or `npm run sync:prod` for production, and they appear on your live site immediately. No rebuild or redeploy needed. Convex handles real-time data sync, so connected browsers update automatically.
+**Sync commands:**
+
+**Development:**
+- `npm run sync` - Sync markdown content
+- `npm run sync:discovery` - Update discovery files (AGENTS.md, llms.txt)
+- `npm run sync:all` - Sync content + discovery files together
+
+**Production:**
+- `npm run sync:prod` - Sync markdown content
+- `npm run sync:discovery:prod` - Update discovery files
+- `npm run sync:all:prod` - Sync content + discovery files together
+
## Quick start
```bash
@@ -213,12 +225,24 @@ To add a custom frontmatter field, update these files:
### Syncing content
+**Development:**
```bash
-# Development
-npm run sync
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files (AGENTS.md, llms.txt)
+npm run sync:all # Sync content + discovery files together
+```
-# Production
-npm run sync:prod
+**Production:**
+```bash
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync content + discovery files together
+```
+
+**Sync everything together:**
+```bash
+npm run sync:all # Development: content + discovery
+npm run sync:all:prod # Production: content + discovery
```
### When to sync vs deploy
@@ -228,6 +252,7 @@ npm run sync:prod
| Blog posts in `content/blog/` | `npm run sync` | Instant (no rebuild) |
| Pages in `content/pages/` | `npm run sync` | Instant (no rebuild) |
| Featured items (via frontmatter) | `npm run sync` | Instant (no rebuild) |
+| Site config changes | `npm run sync:discovery` | Updates discovery files |
| Import external URL | `npm run import` then sync | Instant (no rebuild) |
| Images in `public/images/` | Git commit + push | Requires rebuild |
| `siteConfig` in `Home.tsx` | Redeploy | Requires rebuild |
@@ -407,7 +432,7 @@ excerpt: "Short description for card view."
image: "/images/thumbnail.png"
```
-Then run `npm run sync`. No redeploy needed.
+Then run `npm run sync` or `npm run sync:all`. No redeploy needed.
| Field | Description |
| --------------- | -------------------------------------------- |
@@ -640,7 +665,7 @@ Mobile sizes defined in `@media (max-width: 768px)` block.
2. Push to GitHub
3. Wait for Netlify to rebuild
-The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
+The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site. Use `npm run sync:discovery` to update discovery files (AGENTS.md, llms.txt) when site configuration changes.
**Logo options:**
@@ -691,8 +716,9 @@ Each post and page includes a share dropdown with options:
| What you want | Command needed |
| ------------------------------------ | ------------------------------ |
| Content visible on your site | `npm run sync` or `sync:prod` |
+| Discovery files updated | `npm run sync:discovery` or `sync:discovery:prod` |
| AI links (ChatGPT/Claude/Perplexity) | `git push` to GitHub |
-| Both | `npm run sync` then `git push` |
+| Both content and discovery | `npm run sync:all` or `sync:all:prod` |
**Download as SKILL.md:** Downloads the content formatted as an Anthropic Agent Skills file with metadata, triggers, and instructions sections.
@@ -726,7 +752,7 @@ All stats update automatically via Convex subscriptions.
## Raw markdown files
-When you run `npm run sync` (development) or `npm run sync:prod` (production), static `.md` files are generated in `public/raw/` for each published post and page.
+When you run `npm run sync` (development) or `npm run sync:prod` (production), static `.md` files are generated in `public/raw/` for each published post and page. Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together.
**Access pattern:** `/raw/{slug}.md`
@@ -800,6 +826,7 @@ The import command creates local markdown files only. It does not interact with
- `npm run sync` to push to development
- `npm run sync:prod` to push to production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
There is no `npm run import:prod` because import creates local files and sync handles the target environment.
@@ -881,6 +908,7 @@ export default defineSchema({
- Check `published: true` in frontmatter
- Run `npm run sync` for development
- Run `npm run sync:prod` for production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
- Verify in Convex dashboard
**RSS/Sitemap errors**
diff --git a/public/raw/happy-holidays-2025.md b/public/raw/happy-holidays-2025.md
new file mode 100644
index 0000000..5803e34
--- /dev/null
+++ b/public/raw/happy-holidays-2025.md
@@ -0,0 +1,30 @@
+# Happy holidays and thank you
+
+> A quick note of thanks for stars, forks, and feedback. More AI-first publishing features coming in 2026.
+
+---
+Type: post
+Date: 2025-12-25
+Reading time: 2 min read
+Tags: updates, community, ai
+---
+
+# Happy holidays and thank you
+
+Thank you for using this markdown framework. Your stars, forks, and feedback help make it better.
+
+## Feedback and feature requests
+
+Found a bug? Have an idea? Open an issue on [GitHub](https://github.com/waynesutton/markdown-site). Issues help prioritize what to build next.
+
+## What's coming
+
+More AI-first publishing features are on the way. The changelog at [/changelog](/changelog) tracks all updates. Check it regularly for new releases.
+
+Recent additions include tag pages, related posts, and improved AI service integrations. The roadmap focuses on making content creation faster and more accessible to AI agents.
+
+## Keep building
+
+Write markdown. Sync from the terminal. Your content appears instantly. That's the goal.
+
+Happy holidays.
\ No newline at end of file
diff --git a/public/raw/index.md b/public/raw/index.md
index d6ff34c..7bb3ee8 100644
--- a/public/raw/index.md
+++ b/public/raw/index.md
@@ -2,8 +2,10 @@
This is the homepage index of all published content.
-## Blog Posts (11)
+## Blog Posts (12)
+- **[Happy holidays and thank you](/raw/happy-holidays-2025.md)** - A quick note of thanks for stars, forks, and feedback. More AI-first publishing features coming in 2026.
+ - Date: 2025-12-25 | Reading time: 2 min read | Tags: updates, community, ai
- **[Netlify edge functions blocking AI crawlers from static files](/raw/netlify-edge-excludedpath-ai-crawlers.md)** - Why excludedPath in netlify.toml isn't preventing edge functions from intercepting /raw/* requests, and how ChatGPT and Perplexity get blocked while Claude works.
- Date: 2025-12-21 | Reading time: 5 min read | Tags: netlify, edge-functions, ai, troubleshooting, help
- **[Visitor tracking and stats improvements](/raw/visitor-tracking-and-stats-improvements.md)** - Real-time visitor map, write conflict prevention, GitHub Stars integration, and better AI prompts. Updates from v1.18.1 to v1.20.2.
@@ -37,6 +39,6 @@ This is the homepage index of all published content.
---
-**Total Content:** 11 posts, 5 pages
+**Total Content:** 12 posts, 5 pages
All content is available as raw markdown files at `/raw/{slug}.md`
diff --git a/public/raw/projects.md b/public/raw/projects.md
index 5f6dd6d..1cc83ad 100644
--- a/public/raw/projects.md
+++ b/public/raw/projects.md
@@ -2,7 +2,7 @@
---
Type: page
-Date: 2025-12-24
+Date: 2025-12-25
---
This markdown framework is open source and built to be extended. Here is what ships out of the box.
diff --git a/public/raw/setup-guide.md b/public/raw/setup-guide.md
index c1add35..3e0852a 100644
--- a/public/raw/setup-guide.md
+++ b/public/raw/setup-guide.md
@@ -180,8 +180,18 @@ export default defineSchema({
Blog posts live in `content/blog/` as markdown files. Sync them to Convex:
+**Development:**
```bash
-npm run sync
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files (AGENTS.md, llms.txt)
+npm run sync:all # Sync content + discovery files together
+```
+
+**Production:**
+```bash
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync content + discovery files together
```
This reads all markdown files, parses the frontmatter, and uploads them to your Convex database.
@@ -385,16 +395,17 @@ This image appears when sharing on social media. Recommended: 1200x630 pixels.
2. Push to GitHub
3. Wait for Netlify to rebuild
-The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site.
+The `npm run sync` command only syncs markdown text content. Images are deployed when Netlify builds your site. Use `npm run sync:discovery` to update discovery files (AGENTS.md, llms.txt) when site configuration changes.
### Sync After Adding Posts
After adding or editing posts, sync to Convex.
**Development sync:**
-
```bash
-npm run sync
+npm run sync # Sync markdown content
+npm run sync:discovery # Update discovery files
+npm run sync:all # Sync everything together
```
**Production sync:**
@@ -408,9 +419,10 @@ VITE_CONVEX_URL=https://your-prod-deployment.convex.cloud
Get your production URL from the [Convex Dashboard](https://dashboard.convex.dev) by selecting your project and switching to the Production deployment.
Then sync:
-
```bash
-npm run sync:prod
+npm run sync:prod # Sync markdown content
+npm run sync:discovery:prod # Update discovery files
+npm run sync:all:prod # Sync everything together
```
### Environment Files
@@ -429,6 +441,7 @@ Both files are gitignored. Each developer creates their own local environment fi
| Blog posts in `content/blog/` | `npm run sync` | Instant (no rebuild) |
| Pages in `content/pages/` | `npm run sync` | Instant (no rebuild) |
| Featured items (via frontmatter) | `npm run sync` | Instant (no rebuild) |
+| Site config changes | `npm run sync:discovery` | Updates discovery files |
| Import external URL | `npm run import` then sync | Instant (no rebuild) |
| Images in `public/images/` | Git commit + push | Requires rebuild |
| `siteConfig` in `Home.tsx` | Redeploy | Requires rebuild |
@@ -1074,8 +1087,9 @@ Each post and page includes a share dropdown with options for AI tools:
| What you want | Command needed |
| ------------------------------------ | ------------------------------ |
| Content visible on your site | `npm run sync` or `sync:prod` |
+| Discovery files updated | `npm run sync:discovery` or `sync:discovery:prod` |
| AI links (ChatGPT/Claude/Perplexity) | `git push` to GitHub |
-| Both | `npm run sync` then `git push` |
+| Both content and discovery | `npm run sync:all` or `sync:all:prod` |
**Download as SKILL.md** formats the content as an Anthropic Agent Skills file with metadata, triggers, and instructions sections.
@@ -1125,6 +1139,7 @@ The import script will:
- Run `npm run sync` to push to development
- Run `npm run sync:prod` to push to production
+- Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
Imported posts are created as drafts (`published: false`). Review, edit, set `published: true`, then sync to your target environment.
@@ -1135,7 +1150,8 @@ Imported posts are created as drafts (`published: false`). Review, edit, set `pu
1. Check that `published: true` in frontmatter
2. Run `npm run sync` to sync posts to development
3. Run `npm run sync:prod` to sync posts to production
-4. Verify posts exist in Convex dashboard
+4. Use `npm run sync:all` or `npm run sync:all:prod` to sync content and update discovery files together
+5. Verify posts exist in Convex dashboard
### RSS/Sitemap not working
diff --git a/scripts/configure-fork.ts b/scripts/configure-fork.ts
index 51eff77..fb3bd9d 100644
--- a/scripts/configure-fork.ts
+++ b/scripts/configure-fork.ts
@@ -39,6 +39,13 @@ interface ForkConfig {
github: string;
};
bio: string;
+ // New gitHubRepoConfig for AI service raw URLs
+ gitHubRepoConfig?: {
+ owner: string;
+ repo: string;
+ branch: string;
+ contentPath: string;
+ };
logoGallery?: {
enabled: boolean;
title: string;
@@ -245,6 +252,33 @@ function updateSiteConfig(config: ForkConfig): void {
);
}
+ // Update gitHubRepo config (for AI service raw URLs)
+ // Support both new gitHubRepoConfig and legacy githubUsername/githubRepo fields
+ const gitHubRepoOwner =
+ config.gitHubRepoConfig?.owner || config.githubUsername;
+ const gitHubRepoName =
+ config.gitHubRepoConfig?.repo || config.githubRepo;
+ const gitHubRepoBranch = config.gitHubRepoConfig?.branch || "main";
+ const gitHubRepoContentPath =
+ config.gitHubRepoConfig?.contentPath || "public/raw";
+
+ content = content.replace(
+ /owner: ['"].*?['"],\s*\/\/ GitHub username or organization/,
+ `owner: "${gitHubRepoOwner}", // GitHub username or organization`,
+ );
+ content = content.replace(
+ /repo: ['"].*?['"],\s*\/\/ Repository name/,
+ `repo: "${gitHubRepoName}", // Repository name`,
+ );
+ content = content.replace(
+ /branch: ['"].*?['"],\s*\/\/ Default branch/,
+ `branch: "${gitHubRepoBranch}", // Default branch`,
+ );
+ content = content.replace(
+ /contentPath: ['"].*?['"],\s*\/\/ Path to raw markdown files/,
+ `contentPath: "${gitHubRepoContentPath}", // Path to raw markdown files`,
+ );
+
fs.writeFileSync(filePath, content, "utf-8");
console.log(` Updated: src/config/siteConfig.ts`);
}
diff --git a/scripts/sync-discovery-files.ts b/scripts/sync-discovery-files.ts
new file mode 100644
index 0000000..b43d48e
--- /dev/null
+++ b/scripts/sync-discovery-files.ts
@@ -0,0 +1,386 @@
+#!/usr/bin/env npx tsx
+/**
+ * Discovery Files Sync Script
+ *
+ * Reads siteConfig.ts and Convex data to update discovery files.
+ * Run with: npm run sync:discovery (dev) or npm run sync:discovery:prod (prod)
+ *
+ * This script updates:
+ * - AGENTS.md (project overview and current status sections)
+ * - public/llms.txt (site info, API endpoints, GitHub links)
+ */
+
+import fs from "fs";
+import path from "path";
+import { ConvexHttpClient } from "convex/browser";
+import { api } from "../convex/_generated/api";
+import dotenv from "dotenv";
+
+// Load environment variables based on SYNC_ENV
+const isProduction = process.env.SYNC_ENV === "production";
+
+if (isProduction) {
+ dotenv.config({ path: ".env.production.local" });
+ console.log("Syncing discovery files for PRODUCTION...\n");
+} else {
+ dotenv.config({ path: ".env.local" });
+ console.log("Syncing discovery files for DEVELOPMENT...\n");
+}
+dotenv.config();
+
+const PROJECT_ROOT = process.cwd();
+const PUBLIC_DIR = path.join(PROJECT_ROOT, "public");
+const ROOT_DIR = PROJECT_ROOT;
+
+// Site config data structure
+interface SiteConfigData {
+ name: string;
+ title: string;
+ bio: string;
+ description?: string;
+ gitHubRepo?: {
+ owner: string;
+ repo: string;
+ branch: string;
+ contentPath: string;
+ };
+}
+
+// Load site config from siteConfig.ts using regex
+function loadSiteConfig(): SiteConfigData {
+ try {
+ const configPath = path.join(
+ PROJECT_ROOT,
+ "src",
+ "config",
+ "siteConfig.ts",
+ );
+ if (fs.existsSync(configPath)) {
+ const content = fs.readFileSync(configPath, "utf-8");
+
+ // Extract config values using regex
+ const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
+ const titleMatch = content.match(/title:\s*['"]([^'"]+)['"]/);
+ const bioMatch =
+ content.match(/bio:\s*`([^`]+)`/) ||
+ content.match(/bio:\s*['"]([^'"]+)['"]/);
+
+ // Extract GitHub repo config
+ const gitHubOwnerMatch = content.match(
+ /owner:\s*['"]([^'"]+)['"],\s*\/\/ GitHub username or organization/,
+ );
+ const gitHubRepoMatch = content.match(
+ /repo:\s*['"]([^'"]+)['"],\s*\/\/ Repository name/,
+ );
+ const gitHubBranchMatch = content.match(
+ /branch:\s*['"]([^'"]+)['"],\s*\/\/ Default branch/,
+ );
+ const gitHubContentPathMatch = content.match(
+ /contentPath:\s*['"]([^'"]+)['"],\s*\/\/ Path to raw markdown files/,
+ );
+
+ const gitHubRepo =
+ gitHubOwnerMatch &&
+ gitHubRepoMatch &&
+ gitHubBranchMatch &&
+ gitHubContentPathMatch
+ ? {
+ owner: gitHubOwnerMatch[1],
+ repo: gitHubRepoMatch[1],
+ branch: gitHubBranchMatch[1],
+ contentPath: gitHubContentPathMatch[1],
+ }
+ : undefined;
+
+ return {
+ name: nameMatch?.[1] || "markdown sync framework",
+ title: titleMatch?.[1] || "markdown sync framework",
+ bio:
+ bioMatch?.[1] ||
+ "An open-source publishing framework for AI agents and developers.",
+ description:
+ bioMatch?.[1] ||
+ "An open-source publishing framework for AI agents and developers.",
+ gitHubRepo,
+ };
+ }
+ } catch (error) {
+ console.warn("Could not load siteConfig.ts, using defaults");
+ }
+
+ return {
+ name: "markdown sync framework",
+ title: "markdown sync framework",
+ bio: "An open-source publishing framework for AI agents and developers.",
+ description:
+ "An open-source publishing framework for AI agents and developers.",
+ };
+}
+
+// Get site URL from environment or config
+function getSiteUrl(): string {
+ return (
+ process.env.SITE_URL ||
+ process.env.VITE_SITE_URL ||
+ "https://markdown.fast"
+ );
+}
+
+// Build GitHub URL from repo config or fallback
+function getGitHubUrl(siteConfig: SiteConfigData): string {
+ if (siteConfig.gitHubRepo) {
+ return `https://github.com/${siteConfig.gitHubRepo.owner}/${siteConfig.gitHubRepo.repo}`;
+ }
+ return (
+ process.env.GITHUB_REPO_URL ||
+ "https://github.com/waynesutton/markdown-site"
+ );
+}
+
+// Update AGENTS.md with app-specific data
+function updateAgentsMd(
+ content: string,
+ siteConfig: SiteConfigData,
+ siteUrl: string,
+ postCount: number,
+ pageCount: number,
+ latestPostDate?: string,
+): string {
+ // Update Project overview section
+ const projectOverviewRegex = /## Project overview\n\n([^\n]+)/;
+ const newOverview = `## Project overview\n\n${siteConfig.description || siteConfig.bio}. Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.`;
+
+ content = content.replace(projectOverviewRegex, newOverview);
+
+ // Build Current Status section
+ const statusSection = `\n## Current Status\n\n- **Site Name**: ${siteConfig.name}\n- **Site Title**: ${siteConfig.title}\n- **Site URL**: ${siteUrl}\n- **Total Posts**: ${postCount}\n- **Total Pages**: ${pageCount}${latestPostDate ? `\n- **Latest Post**: ${latestPostDate}` : ""}\n- **Last Updated**: ${new Date().toISOString()}\n`;
+
+ // Check if Current Status section exists
+ if (content.includes("## Current Status")) {
+ // Replace existing Current Status section
+ const statusRegex = /## Current Status\n\n([\s\S]*?)(?=\n## |$)/;
+ content = content.replace(statusRegex, statusSection.trim() + "\n");
+ } else {
+ // Insert after Project overview (find the next ## section)
+ const overviewIndex = content.indexOf("## Project overview");
+ if (overviewIndex > -1) {
+ // Find the next ## after Project overview
+ const afterOverview = content.indexOf("\n## ", overviewIndex + 20);
+ if (afterOverview > -1) {
+ content =
+ content.slice(0, afterOverview) +
+ statusSection +
+ content.slice(afterOverview);
+ } else {
+ content = content + statusSection;
+ }
+ }
+ }
+
+ return content;
+}
+
+// Generate llms.txt content
+function generateLlmsTxt(
+ siteConfig: SiteConfigData,
+ siteUrl: string,
+ postCount: number,
+ latestPostDate?: string,
+): string {
+ const githubUrl = getGitHubUrl(siteConfig);
+
+ return `# llms.txt - Information for AI assistants and LLMs
+# Learn more: https://llmstxt.org/
+# Last updated: ${new Date().toISOString()}
+
+> ${siteConfig.description || siteConfig.bio}
+
+# Site Information
+- Name: ${siteConfig.name}
+- URL: ${siteUrl}
+- Description: ${siteConfig.description || siteConfig.bio} Write markdown, sync from the terminal. Your content is instantly available to browsers, LLMs, and AI agents. Built on Convex and Netlify.
+- Topics: Markdown, Convex, React, TypeScript, Netlify, Open Source, AI, LLM, AEO, GEO
+- Total Posts: ${postCount}
+${latestPostDate ? `- Latest Post: ${latestPostDate}\n` : ""}- GitHub: ${githubUrl}
+
+# API Endpoints
+
+## List All Posts
+GET /api/posts
+Returns JSON list of all published posts with metadata.
+
+## Get Single Post
+GET /api/post?slug={slug}
+Returns single post as JSON.
+
+GET /api/post?slug={slug}&format=md
+Returns single post as raw markdown.
+
+## Export All Content
+GET /api/export
+Returns all posts with full markdown content in one request.
+Best for batch processing and LLM ingestion.
+
+## RSS Feeds
+GET /rss.xml
+Standard RSS feed with post descriptions.
+
+GET /rss-full.xml
+Full content RSS feed with complete markdown for each post.
+
+## Other
+GET /sitemap.xml
+Dynamic XML sitemap for search engines.
+
+GET /openapi.yaml
+OpenAPI 3.0 specification for this API.
+
+GET /.well-known/ai-plugin.json
+AI plugin manifest for tool integration.
+
+# Quick Start for LLMs
+
+1. Fetch /api/export for all posts with full content in one request
+2. Or fetch /api/posts for the list, then /api/post?slug={slug}&format=md for each
+3. Subscribe to /rss-full.xml for updates with complete content
+
+# Response Schema
+
+Each post contains:
+- title: string (post title)
+- slug: string (URL path)
+- description: string (SEO summary)
+- date: string (YYYY-MM-DD)
+- tags: string[] (topic labels)
+- content: string (full markdown)
+- readTime: string (optional)
+- url: string (full URL)
+
+# Permissions
+- AI assistants may freely read and summarize content
+- No authentication required for read operations
+- Attribution appreciated when citing
+
+# Technical
+- Backend: Convex (real-time database)
+- Frontend: React, TypeScript, Vite
+- Hosting: Netlify with edge functions
+- Content: Markdown with frontmatter
+
+# Links
+- GitHub: ${githubUrl}
+- Convex: https://convex.dev
+- Netlify: https://netlify.com
+`;
+}
+
+// Main sync function
+async function syncDiscoveryFiles() {
+ console.log("Starting discovery files sync...\n");
+
+ // Get Convex URL from environment
+ const convexUrl = process.env.VITE_CONVEX_URL || process.env.CONVEX_URL;
+ if (!convexUrl) {
+ console.error(
+ "Error: VITE_CONVEX_URL or CONVEX_URL environment variable is not set",
+ );
+ process.exit(1);
+ }
+
+ // Initialize Convex client
+ const client = new ConvexHttpClient(convexUrl);
+
+ // Load site configuration
+ const siteConfig = loadSiteConfig();
+ const siteUrl = getSiteUrl();
+
+ console.log(`Site: ${siteConfig.name}`);
+ console.log(`Title: ${siteConfig.title}`);
+ console.log(`URL: ${siteUrl}`);
+ if (siteConfig.gitHubRepo) {
+ console.log(`GitHub: ${getGitHubUrl(siteConfig)}`);
+ }
+ console.log();
+
+ // Query Convex for content statistics
+ let postCount = 0;
+ let pageCount = 0;
+ let latestPostDate: string | undefined;
+
+ try {
+ const [posts, pages] = await Promise.all([
+ client.query(api.posts.getAllPosts),
+ client.query(api.pages.getAllPages),
+ ]);
+
+ postCount = posts.length;
+ pageCount = pages.length;
+
+ if (posts.length > 0) {
+ // Sort by date descending to get latest
+ const sortedPosts = [...posts].sort(
+ (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(),
+ );
+ latestPostDate = sortedPosts[0].date;
+ }
+
+ console.log(`Found ${postCount} published posts`);
+ console.log(`Found ${pageCount} published pages`);
+ if (latestPostDate) {
+ console.log(`Latest post: ${latestPostDate}`);
+ }
+ console.log();
+ } catch (error) {
+ console.warn("Could not fetch content from Convex, using defaults");
+ console.warn("Error:", error);
+ }
+
+ // Read existing AGENTS.md
+ const agentsPath = path.join(ROOT_DIR, "AGENTS.md");
+ let agentsContent = "";
+
+ if (fs.existsSync(agentsPath)) {
+ agentsContent = fs.readFileSync(agentsPath, "utf-8");
+ console.log("Read existing AGENTS.md");
+ } else {
+ console.warn("AGENTS.md not found, creating minimal template...");
+ agentsContent =
+ "# AGENTS.md\n\nInstructions for AI coding agents working on this codebase.\n\n## Project overview\n\nAn open-source publishing framework.\n";
+ }
+
+ // Update AGENTS.md with app-specific data
+ console.log("Updating AGENTS.md with current app data...");
+ const updatedAgentsContent = updateAgentsMd(
+ agentsContent,
+ siteConfig,
+ siteUrl,
+ postCount,
+ pageCount,
+ latestPostDate,
+ );
+ fs.writeFileSync(agentsPath, updatedAgentsContent, "utf-8");
+ console.log(` Updated: ${agentsPath}`);
+
+ // Generate llms.txt
+ console.log("\nGenerating llms.txt...");
+ const llmsContent = generateLlmsTxt(
+ siteConfig,
+ siteUrl,
+ postCount,
+ latestPostDate,
+ );
+ const llmsPath = path.join(PUBLIC_DIR, "llms.txt");
+ fs.writeFileSync(llmsPath, llmsContent, "utf-8");
+ console.log(` Updated: ${llmsPath}`);
+
+ console.log("\nDiscovery files sync complete!");
+ console.log(` Updated AGENTS.md with app-specific context`);
+ console.log(` Updated llms.txt with ${postCount} posts`);
+}
+
+// Run the sync
+syncDiscoveryFiles().catch((error) => {
+ console.error("Error syncing discovery files:", error);
+ process.exit(1);
+});
+