Files
wiki/FORK_CONFIG.md

35 KiB

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.


Run a single command to configure all files automatically.

Step 1: Create your config file

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

{
  "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

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

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:

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

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

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

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

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

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

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:

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

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:

{
  "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:

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

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

Manual Configuration

In src/config/siteConfig.ts:

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:

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

Use a blog post as homepage:

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

Switch back to default homepage:

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

{
  "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:

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:

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

Or force show it even if posts default is disabled:

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

Sending Newsletters

To send a newsletter for a specific post:

npm run newsletter:send setup-guide

Or use the Convex CLI directly:

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:

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:

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

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:

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:

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
  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 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 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:
npm run sync-server
  1. The server runs on localhost:3001 and is automatically detected by the dashboard
  2. 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

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

Manual Configuration

In src/config/siteConfig.ts:

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

{
  "imageLightbox": {
    "enabled": true
  }
}

Manual Configuration

In src/config/siteConfig.ts:

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

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

Manual Configuration

In src/config/siteConfig.ts:

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

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:

---
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.


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

In fork-config.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:

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.


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

In fork-config.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:

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

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

Manual Configuration

In src/config/siteConfig.ts:

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:

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

{
  "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:

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:

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

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

Manual Configuration

In src/config/siteConfig.ts:

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