# Fork Configuration Guide

After forking this repo, update these files with your site information. Choose one of two options:

**Important**: Keep your `fork-config.json` file after configuring. The `sync:discovery` commands will use it to update discovery files (`AGENTS.md`, `CLAUDE.md`, `public/llms.txt`) with your configured values.

---

## Option 1: Automated Script (Recommended)

Run a single command to configure all files automatically.

### Step 1: Create your config file

```bash
cp fork-config.json.example fork-config.json
```

The file `fork-config.json` is gitignored, so your configuration stays local and is not committed. The `.example` file remains as a template.

**Keep this file**: Even after running `npm run configure`, keep the `fork-config.json` file. Future sync commands will use it to maintain your configuration.

### Step 2: Edit fork-config.json

```json
{
  "siteName": "Your Site Name",
  "siteTitle": "Your Tagline",
  "siteDescription": "A one-sentence description of your site.",
  "siteUrl": "https://yoursite.netlify.app",
  "siteDomain": "yoursite.netlify.app",
  "githubUsername": "yourusername",
  "githubRepo": "your-repo-name",
  "contactEmail": "you@example.com",
  "creator": {
    "name": "Your Name",
    "twitter": "https://x.com/yourhandle",
    "linkedin": "https://www.linkedin.com/in/yourprofile/",
    "github": "https://github.com/yourusername"
  },
  "bio": "Your bio text here.",
  "theme": "tan"
}
```

### Step 3: Run the configuration script

```bash
npm run configure
```

This updates all 14 configuration files automatically:

- `src/config/siteConfig.ts` (site name, bio, GitHub username, gitHubRepo config, default theme)
- `src/pages/Home.tsx` (intro paragraph, footer links)
- `src/pages/Post.tsx` (SITE_URL, SITE_NAME constants)
- `src/pages/DocsPage.tsx` (SITE_URL constant for CopyPageDropdown)
- `convex/http.ts` (SITE_URL, SITE_NAME constants)
- `convex/rss.ts` (SITE_URL, SITE_TITLE, SITE_DESCRIPTION)
- `netlify/edge-functions/mcp.ts` (SITE_URL, SITE_NAME, MCP_SERVER_NAME)
- `scripts/send-newsletter.ts` (default SITE_URL)
- `index.html` (meta tags, JSON-LD, page title)
- `public/llms.txt` (site info, GitHub link)
- `public/robots.txt` (sitemap URL)
- `public/openapi.yaml` (server URL, site name, example URLs)
- `public/.well-known/ai-plugin.json` (plugin metadata)

### Step 4: Review and deploy

```bash
git diff                    # Review changes
npx convex dev              # Start Convex (if not running)
npm run sync                # Sync content
npm run dev                 # Test locally
```

---

## Option 2: Manual Configuration

Edit each file individually following the guide below.

### Files to Update

| File                                | What to Update                                               |
| ----------------------------------- | ------------------------------------------------------------ |
| `src/config/siteConfig.ts`          | Site name, bio, GitHub username, gitHubRepo config, default theme, features |
| `src/pages/Home.tsx`                | Intro paragraph, footer links                                |
| `src/pages/Post.tsx`                | `SITE_URL`, `SITE_NAME` constants                            |
| `src/pages/DocsPage.tsx`            | `SITE_URL` constant                                          |
| `convex/http.ts`                    | `SITE_URL`, `SITE_NAME` constants                            |
| `convex/rss.ts`                     | `SITE_URL`, `SITE_TITLE`, `SITE_DESCRIPTION`                 |
| `netlify/edge-functions/mcp.ts`     | `SITE_URL`, `SITE_NAME`, `MCP_SERVER_NAME` constants         |
| `scripts/send-newsletter.ts`        | Default `SITE_URL` constant                                  |
| `index.html`                        | Meta tags, JSON-LD, page title                               |
| `public/llms.txt`                   | Site info, GitHub link                                       |
| `public/robots.txt`                 | Sitemap URL                                                  |
| `public/openapi.yaml`               | Server URL, site name, example URLs                          |
| `public/.well-known/ai-plugin.json` | Plugin metadata                                              |

---

## Manual Configuration Details

### 1. src/config/siteConfig.ts

Update the main site configuration:

```typescript
export const siteConfig: SiteConfig = {
  name: "YOUR SITE NAME",
  title: "YOUR TAGLINE",
  logo: "/images/logo.svg", // or null to hide
  intro: null,
  bio: `YOUR BIO TEXT HERE.`,

  // Featured section
  featuredViewMode: "cards", // 'list' or 'cards'
  featuredTitle: "Get started:", // Featured section title (e.g., "Get started:", "Featured", "Popular")
  showViewToggle: true,

  // Logo gallery (set enabled: false to hide)
  logoGallery: {
    enabled: true,
    images: [
      { src: "/images/logos/your-logo.svg", href: "https://example.com" },
    ],
    position: "above-footer",
    speed: 30,
    title: "Built with",
    scrolling: false,
    maxItems: 4,
  },

  // GitHub contributions graph
  gitHubContributions: {
    enabled: true,
    username: "YOURUSERNAME",
    showYearNavigation: true,
    linkToProfile: true,
    title: "GitHub Activity",
  },

  // Visitor map (stats page)
  visitorMap: {
    enabled: true,
    title: "Live Visitors",
  },

  // Blog page
  blogPage: {
    enabled: true,
    showInNav: true,
    title: "Blog",
    description: "All posts from the blog, sorted by date.",
    order: 2,
  },

  // Posts display
  postsDisplay: {
    showOnHome: true,
    showOnBlogPage: true,
  },

  // Homepage configuration
  // Set any page or blog post to serve as the homepage
  homepage: {
    type: "default", // Options: "default" (standard Home component), "page" (use a static page), or "post" (use a blog post)
    slug: undefined, // Required if type is "page" or "post" - the slug of the page/post to use
    originalHomeRoute: "/home", // Route to access the original homepage when custom homepage is set
  },

  links: {
    docs: "/setup-guide",
    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
  },

  // Stats page configuration (optional)
  statsPage: {
    enabled: true, // Global toggle for stats page
    showInNav: true, // Show link in navigation (controlled via hardcodedNavItems)
  },

  // Image lightbox configuration (optional)
  imageLightbox: {
    enabled: true, // Enable click-to-magnify for images in posts/pages
  },

  // MCP Server configuration (optional)
  mcpServer: {
    enabled: true, // Global toggle for MCP server
    endpoint: "/mcp", // Endpoint path
    publicRateLimit: 50, // Requests per minute for public access
    authenticatedRateLimit: 1000, // Requests per minute with API key
    requireAuth: false, // Require API key for all requests
  },
};
```

### 2. src/pages/Home.tsx

Update the intro paragraph (lines 96-108):

```tsx
<p className="home-intro">
  YOUR SITE DESCRIPTION HERE.{" "}
  <a
    href="https://github.com/YOURUSERNAME/YOUR-REPO"
    target="_blank"
    rel="noopener noreferrer"
    className="home-text-link"
  >
    Fork it
  </a>
  , customize it, ship it.
</p>
```

Update the footer section (lines 203-271):

```tsx
<section className="home-footer">
  <p className="home-footer-text">
    Built with{" "}
    <a href={siteConfig.links.convex} target="_blank" rel="noopener noreferrer">
      Convex
    </a>{" "}
    for real-time sync and deployed on{" "}
    <a
      href={siteConfig.links.netlify}
      target="_blank"
      rel="noopener noreferrer"
    >
      Netlify
    </a>
    . Read the{" "}
    <a
      href="https://github.com/YOURUSERNAME/YOUR-REPO"
      target="_blank"
      rel="noopener noreferrer"
    >
      project on GitHub
    </a>{" "}
    to fork and deploy your own. View{" "}
    <a href="/stats" className="home-text-link">
      real-time site stats
    </a>
    .
  </p>
  <p></p>
  <br></br>
  <p className="home-footer-text">
    Created by{" "}
    <a
      href="https://x.com/YOURHANDLE"
      target="_blank"
      rel="noopener noreferrer"
    >
      YOUR NAME
    </a>{" "}
    with Convex, Cursor, and Claude. Follow on{" "}
    <a
      href="https://x.com/YOURHANDLE"
      target="_blank"
      rel="noopener noreferrer"
    >
      Twitter/X
    </a>
    ,{" "}
    <a
      href="https://www.linkedin.com/in/YOURPROFILE/"
      target="_blank"
      rel="noopener noreferrer"
    >
      LinkedIn
    </a>
    , and{" "}
    <a
      href="https://github.com/YOURUSERNAME"
      target="_blank"
      rel="noopener noreferrer"
    >
      GitHub
    </a>
    .
  </p>
</section>
```

### 3. src/pages/Post.tsx

Update the site constants (lines 11-13):

```typescript
const SITE_URL = "https://YOURSITE.netlify.app";
const SITE_NAME = "YOUR SITE NAME";
const DEFAULT_OG_IMAGE = "/images/og-default.svg";
```

### 4. convex/http.ts

Update the site configuration (lines 9-10):

```typescript
const SITE_URL = process.env.SITE_URL || "https://YOURSITE.netlify.app";
const SITE_NAME = "YOUR SITE NAME";
```

Also update the `generateMetaHtml` function (lines 233-234):

```typescript
const siteUrl = process.env.SITE_URL || "https://YOURSITE.netlify.app";
const siteName = "YOUR SITE NAME";
```

### 5. convex/rss.ts

Update the RSS configuration (lines 5-8):

```typescript
const SITE_URL = process.env.SITE_URL || "https://YOURSITE.netlify.app";
const SITE_TITLE = "YOUR SITE NAME";
const SITE_DESCRIPTION = "YOUR SITE DESCRIPTION HERE.";
```

### 6. index.html

Update all meta tags and JSON-LD structured data:

```html
<!-- SEO Meta Tags -->
<meta name="description" content="YOUR SITE DESCRIPTION" />
<meta name="author" content="YOUR SITE NAME" />

<!-- Open Graph -->
<meta property="og:title" content="YOUR SITE NAME" />
<meta property="og:description" content="YOUR SITE DESCRIPTION" />
<meta property="og:url" content="https://YOURSITE.netlify.app/" />
<meta property="og:site_name" content="YOUR SITE NAME" />
<meta
  property="og:image"
  content="https://YOURSITE.netlify.app/images/og-default.svg"
/>

<!-- Twitter Card -->
<meta property="twitter:domain" content="YOURSITE.netlify.app" />
<meta property="twitter:url" content="https://YOURSITE.netlify.app/" />
<meta name="twitter:title" content="YOUR SITE NAME" />
<meta name="twitter:description" content="YOUR SITE DESCRIPTION" />
<meta
  name="twitter:image"
  content="https://YOURSITE.netlify.app/images/og-default.svg"
/>

<!-- JSON-LD -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebSite",
    "name": "YOUR SITE NAME",
    "url": "https://YOURSITE.netlify.app",
    "description": "YOUR SITE DESCRIPTION"
  }
</script>

<title>YOUR SITE TITLE</title>
```

### 7. public/llms.txt

Update site information:

```
# Site Information
- Name: YOUR SITE NAME
- URL: https://YOURSITE.netlify.app
- Description: YOUR SITE DESCRIPTION

# Links
- GitHub: https://github.com/YOURUSERNAME/YOUR-REPO
```

### 8. public/robots.txt

Update the header and sitemap URL:

```
# robots.txt for YOUR SITE NAME

Sitemap: https://YOURSITE.netlify.app/sitemap.xml
```

### 9. public/openapi.yaml

Update API title and server URL:

```yaml
info:
  title: YOUR SITE NAME API
  contact:
    url: https://github.com/YOURUSERNAME/YOUR-REPO

servers:
  - url: https://YOURSITE.netlify.app
```

### 10. public/.well-known/ai-plugin.json

Update plugin metadata:

```json
{
  "name_for_human": "YOUR SITE NAME",
  "name_for_model": "your_site_name",
  "description_for_human": "YOUR SITE DESCRIPTION",
  "contact_email": "you@example.com"
}
```

### 11. Default Theme (in siteConfig.ts)

Change the default theme in `src/config/siteConfig.ts`:

```typescript
export const siteConfig: SiteConfig = {
  // ... other config
  defaultTheme: "tan", // Options: "dark", "light", "tan", "cloud"
};
```

---

## Homepage Configuration

You can set any page or blog post to serve as your homepage instead of the default Home component.

### In fork-config.json

```json
{
  "homepage": {
    "type": "page",
    "slug": "about",
    "originalHomeRoute": "/home"
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
homepage: {
  type: "page", // Options: "default", "page", or "post"
  slug: "about", // Required if type is "page" or "post" - the slug of the page/post to use
  originalHomeRoute: "/home", // Route to access the original homepage when custom homepage is set
},
```

### Options

- `type`: `"default"` (standard Home component), `"page"` (use a static page), or `"post"` (use a blog post)
- `slug`: The slug of the page or post to use (required if type is "page" or "post")
- `originalHomeRoute`: Route to access the original homepage (default: "/home")

### Behavior

- Custom homepage uses the page/post's full content and features (sidebar, copy dropdown, footer, etc.)
- Featured section is NOT shown on custom homepage (only on default Home component)
- SEO metadata comes from the page/post's frontmatter
- Original homepage remains accessible at `/home` (or configured route) when custom homepage is set
- Back button is hidden when a page/post is used as the homepage

### Examples

**Use a static page as homepage:**

```typescript
homepage: {
  type: "page",
  slug: "about",
  originalHomeRoute: "/home",
},
```

**Use a blog post as homepage:**

```typescript
homepage: {
  type: "post",
  slug: "welcome-post",
  originalHomeRoute: "/home",
},
```

**Switch back to default homepage:**

```typescript
homepage: {
  type: "default",
  slug: undefined,
  originalHomeRoute: "/home",
},
```

---

## Newsletter Configuration

The newsletter feature integrates with AgentMail for email subscriptions and sending. It is disabled by default.

### Environment Variables

Set these in the Convex dashboard:

| Variable            | Description                                               |
| ------------------- | --------------------------------------------------------- |
| `AGENTMAIL_API_KEY` | Your AgentMail API key                                    |
| `AGENTMAIL_INBOX`   | Your inbox address (e.g., `newsletter@mail.agentmail.to`) |

### In fork-config.json

```json
{
  "newsletter": {
    "enabled": true,
    "agentmail": {
      "inbox": "newsletter@mail.agentmail.to"
    },
    "signup": {
      "home": {
        "enabled": true,
        "position": "above-footer",
        "title": "Stay Updated",
        "description": "Get new posts delivered to your inbox."
      },
      "blogPage": {
        "enabled": true,
        "position": "above-footer",
        "title": "Subscribe",
        "description": "Get notified when new posts are published."
      },
      "posts": {
        "enabled": true,
        "position": "below-content",
        "title": "Enjoyed this post?",
        "description": "Subscribe for more updates."
      }
    }
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
newsletter: {
  enabled: true, // Master switch for newsletter feature
  agentmail: {
    inbox: "newsletter@mail.agentmail.to",
  },
  signup: {
    home: {
      enabled: true,
      position: "above-footer", // or "below-intro"
      title: "Stay Updated",
      description: "Get new posts delivered to your inbox.",
    },
    blogPage: {
      enabled: true,
      position: "above-footer", // or "below-posts"
      title: "Subscribe",
      description: "Get notified when new posts are published.",
    },
    posts: {
      enabled: true,
      position: "below-content",
      title: "Enjoyed this post?",
      description: "Subscribe for more updates.",
    },
  },
},
```

### Frontmatter Override

Hide or show newsletter signup on specific posts using frontmatter:

```yaml
---
title: My Post
newsletter: false # Hide newsletter signup on this post
---
```

Or force show it even if posts default is disabled:

```yaml
---
title: Special Offer Post
newsletter: true # Show newsletter signup on this post
---
```

### Sending Newsletters

To send a newsletter for a specific post:

```bash
npm run newsletter:send setup-guide
```

Or use the Convex CLI directly:

```bash
npx convex run newsletter:sendPostNewsletter '{"postSlug":"setup-guide","siteUrl":"https://yoursite.com","siteName":"Your Site"}'
```

### Subscriber Management

View subscriber count on the `/stats` page. Subscribers are stored in the `newsletterSubscribers` table in Convex.

### Newsletter Admin

The Newsletter Admin UI at `/newsletter-admin` provides a management interface for subscribers and sending newsletters.

**Configuration:**

In `src/config/siteConfig.ts`:

```typescript
newsletterAdmin: {
  enabled: true,      // Enable /newsletter-admin route
  showInNav: false,   // Hide from navigation (access via direct URL)
},
```

**Features:**

- View and search all subscribers
- Filter by status (all, active, unsubscribed)
- Delete subscribers
- Send blog posts as newsletters
- Write and send custom emails with markdown support
- View recent newsletter sends
- Email statistics dashboard

**CLI Commands:**

```bash
# Send a blog post to all subscribers
npm run newsletter:send <post-slug>

# Send weekly stats summary
npm run newsletter:send:stats
```

### Newsletter Notifications

Configure developer notifications for subscriber events:

In `src/config/siteConfig.ts`:

```typescript
newsletterNotifications: {
  enabled: true,              // Global toggle for notifications
  newSubscriberAlert: true,   // Send email when new subscriber signs up
  weeklyStatsSummary: true,   // Send weekly stats summary email
},
```

Uses `AGENTMAIL_CONTACT_EMAIL` or `AGENTMAIL_INBOX` as recipient.

### Weekly Digest

Automated weekly email with posts from the past 7 days:

In `src/config/siteConfig.ts`:

```typescript
weeklyDigest: {
  enabled: true,      // Global toggle for weekly digest
  dayOfWeek: 0,       // 0 = Sunday, 6 = Saturday
  subject: "Weekly Digest", // Email subject prefix
},
```

Runs automatically via cron job every Sunday at 9:00 AM UTC.

### Dashboard

The dashboard at `/dashboard` provides a centralized UI for managing content, configuring the site, and performing sync operations.

**Configuration:**

In `src/config/siteConfig.ts`:

```typescript
dashboard: {
  enabled: true,        // Global toggle for dashboard page
  requireAuth: false,   // Set to true to require WorkOS authentication
},
```

**Authentication:**

WorkOS authentication is optional. When `requireAuth` is `false`, the dashboard is open access. When `requireAuth` is `true` and WorkOS is configured, users must log in to access the dashboard.

**WorkOS Setup:**

To enable WorkOS authentication:

1. Create a WorkOS account at [workos.com](https://workos.com)
2. Set `VITE_WORKOS_CLIENT_ID` in your `.env.local` file
3. Set `VITE_WORKOS_REDIRECT_URI` (e.g., `http://localhost:5173/callback`)
4. Add `WORKOS_CLIENT_ID` to Convex environment variables
5. Configure redirect URI in WorkOS dashboard
6. Set `requireAuth: true` in `siteConfig.ts`

See [How to setup WorkOS](https://www.markdown.fast/how-to-setup-workos) for complete setup instructions.

**Features:**

- Content management: Edit posts and pages with live preview
- Sync commands: Run sync operations from the browser
- Site configuration: Configure all settings via UI
- Newsletter management: Integrated subscriber and email management
- AI Agent: Writing assistance powered by Claude
- Analytics: Real-time stats dashboard

See [How to use the Markdown sync dashboard](https://www.markdown.fast/how-to-use-the-markdown-sync-dashboard) for complete usage guide.

### Dashboard Sync Server

The dashboard includes a sync server feature that allows executing sync commands directly from the browser UI without opening a terminal.

**Setup:**

1. Start the sync server locally:
```bash
npm run sync-server
```

2. The server runs on `localhost:3001` and is automatically detected by the dashboard
3. Optional: Set `SYNC_TOKEN` environment variable for authentication

**Features:**

- Execute sync commands from dashboard UI
- Real-time output streaming in dashboard terminal view
- Server status indicator (online/offline)
- Whitelisted commands only (sync, sync:prod, sync:discovery, sync:discovery:prod, sync:all, sync:all:prod)

---

## Stats Page Configuration

Control access to the `/stats` route for viewing site analytics.

### In fork-config.json

```json
{
  "statsPage": {
    "enabled": true,
    "showInNav": true
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
statsPage: {
  enabled: true, // Global toggle for stats page
  showInNav: true, // Show link in navigation (controlled via hardcodedNavItems)
},
```

**Note:** Navigation visibility is controlled via `hardcodedNavItems` configuration. Set `showInNav: false` on the stats nav item to hide it.

---

## Image Lightbox Configuration

Enable click-to-magnify functionality for images in blog posts and pages.

### In fork-config.json

```json
{
  "imageLightbox": {
    "enabled": true
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
imageLightbox: {
  enabled: true, // Enable click-to-magnify for images
},
```

**Features:**

- Click any image in a post/page to open in full-screen lightbox
- Dark backdrop with close button (X icon)
- Keyboard support: Press Escape to close
- Click outside image (backdrop) to close
- Alt text displayed as caption below image
- Images show pointer cursor (`zoom-in`) when enabled

---

## MCP Server Configuration

HTTP-based Model Context Protocol server for AI tool integration (Cursor, Claude Desktop).

### In fork-config.json

```json
{
  "mcpServer": {
    "enabled": true,
    "endpoint": "/mcp",
    "publicRateLimit": 50,
    "authenticatedRateLimit": 1000,
    "requireAuth": false
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
mcpServer: {
  enabled: true, // Global toggle for MCP server
  endpoint: "/mcp", // Endpoint path
  publicRateLimit: 50, // Requests per minute for public access
  authenticatedRateLimit: 1000, // Requests per minute with API key
  requireAuth: false, // Require API key for all requests
},
```

**Environment Variables:**

Set `MCP_API_KEY` in Netlify environment variables for authenticated access.

**Features:**

- Accessible 24/7 at `https://yoursite.com/mcp`
- Public access with Netlify built-in rate limiting (50 req/min per IP)
- Optional API key authentication for higher limits (1000 req/min)
- Read-only access to blog posts, pages, homepage, and search
- 7 tools: `list_posts`, `get_post`, `list_pages`, `get_page`, `get_homepage`, `search_content`, `export_all`
- JSON-RPC 2.0 protocol over HTTP POST

See [How to Use the MCP Server](https://www.markdown.fast/how-to-use-mcp-server) for client configuration examples.

---

## Contact Form Configuration

Enable contact forms on any page or post via frontmatter. Messages are sent via AgentMail.

### Environment Variables

Set these in the Convex dashboard:

| Variable                  | Description                                                                 |
| ------------------------- | --------------------------------------------------------------------------- |
| `AGENTMAIL_API_KEY`       | Your AgentMail API key                                                      |
| `AGENTMAIL_INBOX`         | Your inbox address for sending (e.g., `newsletter@mail.agentmail.to`)       |
| `AGENTMAIL_CONTACT_EMAIL` | Optional: recipient for contact form messages (defaults to AGENTMAIL_INBOX) |

### Site Config

In `src/config/siteConfig.ts`:

```typescript
contactForm: {
  enabled: true, // Global toggle for contact form feature
  title: "Get in Touch",
  description: "Send us a message and we'll get back to you.",
},
```

**Note:** Recipient email is configured via Convex environment variables (`AGENTMAIL_CONTACT_EMAIL` or `AGENTMAIL_INBOX`). Never hardcode email addresses in code.

### Frontmatter Usage

Enable contact form on any page or post:

```yaml
---
title: Contact Us
slug: contact
contactForm: true
---
```

The form includes name, email, and message fields. Submissions are stored in Convex and sent via AgentMail to the configured recipient.

---

## Footer Configuration

The footer component displays markdown content and can be configured globally or per-page.

### In fork-config.json

```json
{
  "footer": {
    "enabled": true,
    "showOnHomepage": true,
    "showOnPosts": true,
    "showOnPages": true,
    "showOnBlogPage": true,
    "defaultContent": "Built with [Convex](https://convex.dev) for real-time sync."
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
footer: {
  enabled: true,              // Global toggle for footer
  showOnHomepage: true,       // Show footer on homepage
  showOnPosts: true,          // Default: show footer on blog posts
  showOnPages: true,          // Default: show footer on static pages
  showOnBlogPage: true,       // Show footer on /blog page
  defaultContent: "...",      // Default markdown content
},
```

**Frontmatter Override:**

Set `showFooter: false` in post/page frontmatter to hide footer on specific pages. Set `footer: "..."` to provide custom markdown content.

---

## Social Footer Configuration

Display social icons and copyright information below the main footer. Icons can also appear in the header.

### In fork-config.json

```json
{
  "socialFooter": {
    "enabled": true,
    "showOnHomepage": true,
    "showOnPosts": true,
    "showOnPages": true,
    "showOnBlogPage": true,
    "showInHeader": true,
    "socialLinks": [
      {
        "platform": "github",
        "url": "https://github.com/yourusername/your-repo-name"
      },
      {
        "platform": "twitter",
        "url": "https://x.com/yourhandle"
      }
    ],
    "copyright": {
      "siteName": "Your Site Name",
      "showYear": true
    }
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
socialFooter: {
  enabled: true,
  showOnHomepage: true,
  showOnPosts: true,
  showOnPages: true,
  showOnBlogPage: true,
  showInHeader: true, // Show social icons in header (left of search icon)
  socialLinks: [
    { platform: "github", url: "https://github.com/username" },
    { platform: "twitter", url: "https://x.com/handle" },
    { platform: "linkedin", url: "https://linkedin.com/in/profile" },
  ],
  copyright: {
    siteName: "Your Site Name",
    showYear: true, // Auto-updates to current year
  },
},
```

**Supported Platforms:** github, twitter, linkedin, instagram, youtube, tiktok, discord, website

**Header Social Icons:**

When `showInHeader: true`, social icons appear in the navigation header to the left of the search icon on desktop. This provides additional visibility for your social links while maintaining the footer placement.

**Frontmatter Override:**

Set `showSocialFooter: false` in post/page frontmatter to hide social footer on specific pages.

---

## Right Sidebar Configuration

Enable a right sidebar on posts and pages that displays CopyPageDropdown at wide viewport widths.

### In fork-config.json

```json
{
  "rightSidebar": {
    "enabled": true,
    "minWidth": 1135
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
rightSidebar: {
  enabled: true,      // Set to false to disable globally
  minWidth: 1135,    // Minimum viewport width to show sidebar
},
```

**Frontmatter Usage:**

Enable right sidebar on specific posts/pages:

```yaml
---
title: My Post
rightSidebar: true
---
```

**Features:**

- Right sidebar appears at 1135px+ viewport width
- Contains CopyPageDropdown with sharing options
- Three-column layout: left sidebar (TOC), main content, right sidebar
- Hidden below 1135px, CopyPageDropdown returns to nav

---

## AI Chat Configuration

Configure the AI writing assistant. The Dashboard AI Agent supports multiple providers (Anthropic, OpenAI, Google) and includes image generation.

### In fork-config.json

```json
{
  "aiChat": {
    "enabledOnWritePage": false,
    "enabledOnContent": false
  },
  "aiDashboard": {
    "enableImageGeneration": true,
    "defaultTextModel": "claude-sonnet-4-20250514",
    "textModels": [
      { "id": "claude-sonnet-4-20250514", "name": "Claude Sonnet 4", "provider": "anthropic" },
      { "id": "gpt-4o", "name": "GPT-4o", "provider": "openai" },
      { "id": "gemini-2.0-flash", "name": "Gemini 2.0 Flash", "provider": "google" }
    ],
    "imageModels": [
      { "id": "gemini-2.0-flash-exp-image-generation", "name": "Nano Banana", "provider": "google" },
      { "id": "imagen-3.0-generate-002", "name": "Nano Banana Pro", "provider": "google" }
    ]
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
aiChat: {
  enabledOnWritePage: true,  // Show AI chat toggle on /write page
  enabledOnContent: true,    // Allow AI chat on posts/pages via frontmatter
},
aiDashboard: {
  enableImageGeneration: true, // Enable image generation tab in Dashboard AI Agent
  defaultTextModel: "claude-sonnet-4-20250514", // Default model for chat
  textModels: [
    { id: "claude-sonnet-4-20250514", name: "Claude Sonnet 4", provider: "anthropic" },
    { id: "gpt-4o", name: "GPT-4o", provider: "openai" },
    { id: "gemini-2.0-flash", name: "Gemini 2.0 Flash", provider: "google" },
  ],
  imageModels: [
    { id: "gemini-2.0-flash-exp-image-generation", name: "Nano Banana", provider: "google" },
    { id: "imagen-3.0-generate-002", name: "Nano Banana Pro", provider: "google" },
  ],
},
```

**Environment Variables (Convex):**

| Variable | Provider | Features |
| --- | --- | --- |
| `ANTHROPIC_API_KEY` | Anthropic | Claude Sonnet 4 chat |
| `OPENAI_API_KEY` | OpenAI | GPT-4o chat |
| `GOOGLE_AI_API_KEY` | Google | Gemini 2.0 Flash chat + image generation |

**Optional system prompt variables:**

- `CLAUDE_PROMPT_STYLE`, `CLAUDE_PROMPT_COMMUNITY`, `CLAUDE_PROMPT_RULES` (optional): Split system prompts
- `CLAUDE_SYSTEM_PROMPT` (optional): Single system prompt fallback

**Note:** Only configure the API keys for providers you want to use. If a key is not set, users see a helpful setup message when they try to use that model.

**Frontmatter Usage:**

Enable AI chat on posts/pages:

```yaml
---
title: My Post
rightSidebar: true
aiChat: true
---
```

Requires `rightSidebar: true` and `siteConfig.aiChat.enabledOnContent: true`.

**Dashboard AI Agent Features:**

- **Chat Tab:** Multi-model selector with lazy API key validation
- **Image Tab:** AI image generation with aspect ratio selection (1:1, 16:9, 9:16, 4:3, 3:4)
- Images stored in Convex storage with session tracking
- Gallery view of recent generated images

---

## Posts Display Configuration

Control where posts appear and limit homepage display.

### In fork-config.json

```json
{
  "postsDisplay": {
    "showOnHome": true,
    "showOnBlogPage": true,
    "homePostsLimit": 5,
    "homePostsReadMore": {
      "enabled": true,
      "text": "Read more blog posts",
      "link": "/blog"
    }
  }
}
```

### Manual Configuration

In `src/config/siteConfig.ts`:

```typescript
postsDisplay: {
  showOnHome: true,           // Show post list on homepage
  showOnBlogPage: true,       // Show post list on /blog page
  homePostsLimit: 5,          // Limit posts on homepage (undefined = show all)
  homePostsReadMore: {
    enabled: true,            // Show "read more" link when limited
    text: "Read more blog posts",
    link: "/blog",
  },
},
```

---

## AI Agent Prompt

Copy this prompt to have an AI agent apply all changes:

```
I just forked the markdown-site repo. Please update all configuration files with my site information:

Site Name: [YOUR SITE NAME]
Site Title/Tagline: [YOUR TAGLINE]
Site Description: [YOUR DESCRIPTION]
Site URL: https://[YOURSITE].netlify.app
GitHub Username: [YOURUSERNAME]
GitHub Repo: [YOUR-REPO]
Contact Email: [your@email.com]

Creator Info:
- Name: [YOUR NAME]
- Twitter: https://x.com/[YOURHANDLE]
- 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, gitHubRepo config, defaultTheme
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. src/pages/DocsPage.tsx - SITE_URL constant
5. convex/http.ts - SITE_URL and SITE_NAME constants
6. convex/rss.ts - SITE_URL, SITE_TITLE, SITE_DESCRIPTION
7. netlify/edge-functions/mcp.ts - SITE_URL, SITE_NAME, MCP_SERVER_NAME constants
8. scripts/send-newsletter.ts - default SITE_URL constant
9. index.html - all meta tags, JSON-LD, title
10. public/llms.txt - site info and GitHub link
11. public/robots.txt - header comment and sitemap URL
12. public/openapi.yaml - API title, server URL, contact URL, example URLs
13. public/.well-known/ai-plugin.json - plugin metadata and contact email
```

---

## After Configuration

1. Run `npx convex dev` to initialize Convex
2. Run `npm run sync` to sync content to development
3. Run `npm run dev` to test locally
4. Deploy to Netlify when ready

**Note**: Keep your `fork-config.json` file. When you run `npm run sync:discovery` or `npm run sync:all`, it reads from `fork-config.json` to update discovery files with your site information.

---

## Syncing Discovery Files

Discovery files (`AGENTS.md`, `CLAUDE.md`, and `public/llms.txt`) can be automatically updated with your current app data.

**How it works**: The sync:discovery script reads from `fork-config.json` (if it exists) to get your site name, URL, and GitHub info. This ensures your configured values are preserved when updating discovery files.

### 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:

| File                           | Purpose                    |
| ------------------------------ | -------------------------- |
| `content/blog/*.md`            | Blog posts                 |
| `content/pages/*.md`           | Static pages (About, etc.) |
| `content/pages/home.md`        | Homepage intro content (slug: `home-intro`, uses blog heading styles) |
| `content/pages/footer.md`      | Footer content (slug: `footer`, syncs via markdown, falls back to siteConfig.defaultContent) |
| `public/images/logo.svg`       | Site logo                  |
| `public/images/og-default.svg` | Default social share image |
| `public/images/logos/*.svg`    | Logo gallery images        |
