LightCMS Version History
All notable changes to LightCMS, organized by version. Source: CHANGELOG.md
v7.3 — SEO & AI
See how AI systems read your site, decide what they may do with it, and give them clean, well-attributed content (v7.3.0–v7.3.4).
Added
- AI traffic analytics: A new AI view in Analytics shows which AI crawlers read your site, split by purpose: model training (GPTBot, ClaudeBot, …), AI search (OAI-SearchBot, PerplexityBot, …) and user-initiated fetches (ChatGPT-User, Claude-User, …). It also lists the pages AI reads most and how many visits ChatGPT, Perplexity, Claude, Gemini and Copilot send you, including visits that arrive with a
utm_sourcetag instead of a referrer. A summary is included in CMS Agent digests. - AI crawler controls: Allow or block AI training, AI search and user fetches separately, with per-crawler overrides and an optional Content-Signal line, all rendered into robots.txt. Google and Bing search are untouched unless you say otherwise.
- Markdown copies: Every page is also available as clean Markdown at
/<page>.md, linked from the page and from llms.txt, so AI agents can read it without the HTML. The copies are kept out of search results. - Richer structured data: Authors (site default plus per-page override), publisher logo and profiles, breadcrumbs, FAQ markup from explicit FAQ sections, and “last modified” dates that only change when the page content actually changes.
- RSS & Atom feeds:
/feed.xml,/atom.xmland per-collection feeds with full content. - Hide from search & AI: A per-page switch that adds noindex and removes the page from the sitemap, llms.txt, feeds and IndexNow. The page stays visible to visitors.
- Tools & API: A new SEO & AI settings screen, a REST API, and four MCP tools (128 total).
Fixed
- IndexNow from the editor: Unpublishing, moving or deleting a page in the admin editor now notifies search engines, as API and MCP edits already did.
- Canonical links are now absolute URLs, and Markdown copies keep spaces between adjacent links (v7.3.1).
- Published dates: Pages created already-published through the API, MCP, bulk tools or imports now get a published date, which structured data and feeds rely on. A one-time backfill tool (API and MCP, with a dry-run option) gives older pages their creation date (v7.3.2, 128 MCP tools).
- Sitemap freshness: sitemap.xml now refreshes itself when it’s more than 10 minutes old. Before, only edits made in the admin screens updated it, so pages managed through the API or MCP could go missing or linger after removal (v7.3.3).
- Homepage safety: Deleting an old page with an empty path no longer removes the homepage’s generated file (v7.3.4).
v7.2 — The CMS Agent & IndexNow
A built-in agent that reports on your site, plus instant search-engine notification (v7.2.0–v7.2.5).
Added
- IndexNow (v7.2.3–v7.2.5): When you publish, edit, move, unpublish or delete a page, LightCMS tells Bing, Yandex, Seznam, Naver and other IndexNow search engines right away instead of waiting for a recrawl. No setup needed: each site generates its own key, confirms it really serves its public URL before submitting anything, and submits the whole site once when IndexNow first switches on. Edits are batched, unchanged re-renders are skipped, and each URL is resubmitted at most once every 10 minutes. Status and submission history are under Tools → IndexNow, with three new MCP tools (124 total).
- CMS Agent (v7.2.0): Your site’s built-in agent, starting with configurable email digests: site health, traffic, the review queue (forks, approvals, scheduled posts), agent activity, broken links, and optional AI commentary from Claude. Delivered through Resend; daily, weekdays or weekly at the hour you choose.
Fixed
- Sitemap: sitemap.xml no longer lists deleted pages or sandbox fork copies, and builds faster on large sites (v7.2.3).
- IndexNow follow-ups: Unknown
.txtURLs return 404 instead of the homepage (v7.2.4), and changes made while a search engine is still verifying a new site key are retried instead of dropped (v7.2.5). - CMS Agent feedback: Clear success and failure banners after sending a test digest or saving settings (v7.2.1).
- Analytics: The trend KPI card resets correctly when switching visitor tabs, and edit-link lookups use one lightweight query instead of three full-document loads (v7.2.2).
v7.1 — The Ambient Copilot
The copilot becomes a slide-in drawer on every admin page (v7.1.0–v7.1.1).
Added
- Ambient copilot: A floating button on every admin page opens a slide-in AI copilot — edit, create, and publish content in plain language without leaving your current screen. Fullscreen toggle, ChatGPT-style vertical chat history with full-text search, animated typing indicator with progressive status, and markdown tables rendered as styled tables.
- Copilot analytics & site health: Ask for your most popular pages, top referrers, traffic summaries, or the daily maintenance report (stale pages, missing meta descriptions, lingering drafts).
v7.0.x — Patch Train
Rapid follow-ups to the agentic release (v7.0.1–v7.0.9).
- AI-search output: Homepage schema.org WebSite JSON-LD with SearchAction, including raw-HTML homepages. llms.txt/llms-full.txt queries use projections — ~40s to ~1s on large sites.
- Analytics ranges: 60-day and 90-day presets plus custom date ranges across all analytics views.
- Version visibility: The admin sidebar shows the running software version.
- Fixes: Copilot CSRF token double-quoting; agent-session rollback now selects targets by version provenance (a session’s own versions are never rollback targets), eliminating a timestamp race.
v7.0.0 — The Agentic Release
AI agents become first-class, governed users of the CMS. 115 MCP tools total.
Added
- Agent sandbox (“pull requests for content”): Agents work in copy-on-write fork sandboxes; publishing, deleting, and bulk operations are blocked inside a sandbox, and nothing reaches the live site until a human reviews the per-field diff and merges.
- Agent governance: API keys accept permission scopes and a server-enforced sandbox-only flag. Every agent session has an audit ledger and one-call rollback (created→soft-deleted, deleted→restored, updated→reverted to the pre-session version).
- Change provenance: Every content version records who authored it — human or agent, via which channel, and which session.
- llms.txt + JSON-LD: Auto-generated llms.txt and llms-full.txt for AI crawlers; schema.org structured data (BlogPosting/NewsArticle/WebPage) on all published pages.
- Public read-only MCP: An unauthenticated MCP endpoint at /mcp-public lets visitors’ agents search and read the published site natively. Drafts and forks are structurally excluded.
- Local embeddings: LIGHTCMS_EMBEDDINGS_PROVIDER=ollama generates semantic-search embeddings locally — no hosted API or per-call credits.
- Self-maintaining sites: Daily maintenance scans surface stale pages, missing meta descriptions, and drafts as an agent-ready work queue via API and MCP.
- Module path: Now github.com/jonradoff/lightcms/v7 (semantic import versioning).
v6.1.1 — Security Hardening
Comprehensive security review and fixes for bulk operations and MCP features.
Security
- Search/replace input validation: Pairs array capped at 100 per request. Search and replace text capped at 100K characters. Regex patterns capped at 1,000 characters to prevent ReDoS.
- Legacy API keys deprecated: API keys without an associated user are auto-migrated to the first admin user on first use. Keys must have user context for permission enforcement.
- Script policy at write time: Bulk create and bulk update sanitize content data fields when script policy is admin_only or none, as defense-in-depth alongside render-time enforcement.
- Bulk field operation validation: System fields (_id, published, template_id, full_path, etc.) blocked from modification via bulk field operations.
- Per-page locking: Search/replace, bulk update, and bulk field operations use per-page mutual exclusion to prevent race conditions.
- Error message sanitization: Bulk operation errors no longer expose MongoDB internals. Detailed errors logged server-side only.
- Enhanced audit logging: Bulk create includes sample of created content IDs in audit trail.
v6.1.0 — Bulk Operations, Analytics & Programmatic SEO
Major release focused on scale, observability, and bulk content management for programmatic SEO workflows.
Added
- Bulk Create Content: New bulk_create_content MCP tool creates up to 100 pages per call with parallel HTML generation. Supports upsert mode for retry-safe operations.
- Content Upsert: create_content and bulk_create_content accept upsert: true — updates existing pages instead of failing on duplicates.
- Multi-Pair Search & Replace: Pass a pairs array to apply all replacements in a single O(pages) pass instead of O(pairs × pages).
- Content List Pagination: list_content supports limit (1-500) and offset with {items, total, has_more} envelope.
- Burst Rate Limiting: 20 requests/second per token, complementing the 300/min sliding window.
- Site Analytics Dashboard: Hourly visitor chart with hover tooltips, uptime monitoring strip, top pages by views, top referrers (Non-bot/Bots/All tabs), browser donut chart.
- Per-Page Analytics: View counts, referrer breakdown, and edit links for individual pages at /cm/analytics/page.
- Referrer Drill-Down: Click any referrer domain to see which pages received traffic from that source.
- Analytics Tab on Content Editor: 7d and 30d view counts plus top referrers inline on every content edit page.
- Page View Tracking: Buffered writes (30s flush) for page views, referrers, and user agents with zero performance impact.
Changed
- Search/Replace returns counts: Responses include pages_scanned, pages_modified, total_replacements.
- Conditional Republish: SHA-256 content hashing skips unchanged pages during regeneration.
Fixed
- Analytics data not recording: site_stats collection blocked by Atlas 500-collection limit; moved to user_activity sentinel pattern.
- Analytics chart empty: ISO time format mismatch between Go and JavaScript fixed with epoch-ms keys.
- Buffer flush BSON error: Null byte separator in page_refs keys rejected by BSON; changed to || separator.
v6.0.1 — Security Hardening
Comprehensive security patch addressing 15 issues identified in a full security review of the v6.0.0 API surface.
Security
- CSRF key hardening — CSRF protection key is now derived via SHA-256 hash of the session secret instead of zero-padding, eliminating low-entropy padding.
- OAuth system key user context — The system API key used for OAuth-authenticated MCP sessions is now associated with an admin user. OAuth sessions previously bypassed all permission checks via a nil-user path; they now properly resolve to admin-level RBAC.
- 20+ read-only API endpoints now require login — All
/api/v1/read endpoints (content, templates, assets, snippets, redirects, folders, collections, theme, config, comments) now require viewer-level credentials. Public end-user endpoints (/api/search,/api/chat,/api/contact) are unchanged. - Self-approval blocked — Users can no longer approve their own content submissions.
- Sequential workflow order enforced — Only the approver assigned to the current step may advance a sequential workflow.
- Workflow approver validation — Approver user IDs are validated against real users when creating or updating approval workflows.
- Comment rate limiting & length cap —
POST /api/v1/content/{id}/commentsis rate-limited to 20 req/min per token; text capped at 10,000 characters. - Comment XSS fix —
user_display_nameanduser_emailare HTML-escaped before injection into dynamically created comment DOM nodes and mention dropdowns. - Bulk export gated —
APIExportContentnow requirescontent.editpermission. - Config endpoint auth & token redaction —
GET /api/v1/configrequiressettings.viewpermission; Cloudflare API token is redacted in the response. - Force-unlock RBAC —
APIForceUnlockContentnow usesrequirePermissioninstead of a hardcoded role string check. - Sidebar badge efficiency — Approval badge count now uses
CountPending()(single O(1) query) instead of loading the full pending result set on every admin page render.
v6.0.0 — Content Approvals & Discussions
Adds configurable approval workflows for content publishing, a new Contributor role, and inline threaded discussion threads on every content item.
Content Approvals
- Approval workflows — Configurable trigger-based workflows by contributor, folder path, template ID, or tag. Supports sequential mode (approvers in order) and concurrent mode (any N-of-M).
- Approvals dashboard at
/cm/approvals— Shows “My Queue” and “Other Pending.” Approve/reject with a required rejection comment. Badge count in sidebar nav. - Contributor role — New RBAC role between Viewer and Editor. Contributors can create content and upload assets (held pending), submit for approval, and post discussion comments — but cannot publish directly.
- Dashboard integration — “Requiring Approvals” section and “Recent Comments” section on the admin dashboard.
Content Discussions
- Discussion tab — Inline threaded comment section at the bottom of every content edit page. Live badge count on the tab.
- @mention autocomplete — Type
@in a comment to search and mention other users. - Rejection comments — When an approval request is rejected, the rejection comment is auto-posted to the content discussion thread.
- Tabbed bottom section — Discussion, Version History, and Forks are now organized into tabs on the content edit page.
New MCP Tools (14 added, 92 → 106 total)
list_comments,create_comment,delete_commentlist_approval_workflows,get_approval_workflow,create_approval_workflow,update_approval_workflow,delete_approval_workflowlist_approval_requests,get_approval_request,submit_for_approval,approve_request,reject_request,cancel_approval_request
Webhook Events
- Three new event types:
comment.created,content.pending_approval,asset.pending_review - Messages “Mark All as Read” button added to the contact messages list page
v5.0.0 — Import Pipeline
Adds a unified content import pipeline with support for RSS/Atom feeds, Markdown files, and CSV data — with a live streaming job log and full MCP tool coverage.
Import Types
- RSS/Atom Import — Configure recurring feed sources with schedule (hourly/daily/weekly), template mapping, folder targeting, and auto-publish. Full run history and per-job logs.
- Markdown Import — Upload single
.mdfiles or.ziparchives. YAML frontmatter controls title, slug, folder, template, tags, and scheduling. Supports Notion, Obsidian, Hugo/Jekyll migrations, and AI-generated content. - CSV Import — Upload CSV files and map columns to content fields. Specify the title column; all other columns become fields automatically.
- Deduplication — Imports match by
full_path— re-importing the same slug updates rather than duplicating. - Real-time import status — SSE-powered live log stream at
/cm/imports/{jobID}. - Agentic bulk content creation —
import_markdownis specifically designed for AI agents to generate and import large batches of content in a single call.
New MCP Tools (10 added)
list_import_sources,create_import_source,update_import_source,delete_import_source,trigger_import_sourceimport_markdown,import_csv,list_import_jobs,get_import_job,cancel_import_job
v4.5.0 — Webhooks, Scheduled Publishing & Content Locking
Adds HMAC-signed webhook events, scheduled publishing, collaborative content locking, Cloudflare cache integration, edge caching headers, and structured JSON logging.
- Webhooks — HMAC-SHA256 signed webhook events for content lifecycle. Configurable per-webhook with retry logic and delivery history. Admin UI at
/cm/webhooks. - Scheduled Publishing — Set a future
publish_attimestamp; background scheduler publishes automatically. - Content Locking — Advisory lock when editing (30-minute expiry). Warning banner if another user is editing. Force unlock for admins.
- Incremental Static Regeneration — Template changes regenerate content in batches of 20, preventing server overload.
- Edge Caching Headers — ETag, Cache-Control, Last-Modified, and Vary headers on all public pages. 304 Not Modified support.
- Cloudflare Integration — Configure Zone ID and API Token to automatically purge Cloudflare cache on publish/unpublish.
- Structured JSON Logging — All server logs emit structured JSON with timestamp, level, message, and context fields.
- Rate Limit Dashboard — New tab on the audit log page showing locked IPs, attempt counts, and a clear button.
- MCP Prompt Resources — Three new MCP resources:
lightcms://site/structure,lightcms://content/recent,lightcms://theme/config.
v4.2.0 — AI Chat Widget, Security Hardening & Performance
Adds an embeddable AI-powered chat widget backed by hybrid semantic search, 8 new fork MCP tools (64 → 72 total), major security hardening, and a comprehensive performance overhaul.
AI Chat Widget
- Embeddable widget — Add a floating AI chat bubble to any page with a single
<script>tag. Self-contained JS widget fetches its config from/api/chat/configand streams answers from/api/chat/query. - Two-phase pipeline — Each query runs hybrid semantic+fulltext search to retrieve relevant excerpts, then streams those through Claude Haiku for a conversational synthesized answer — reusing the same infrastructure as
end_user_search. - SSE streaming — Haiku token-by-token output forwarded live to the browser via Server-Sent Events. Falls back to plain JSON for non-SSE clients.
- AI-optional mode — Without an Anthropic API key, the widget still returns ranked search results with excerpts — a useful search-in-chat experience with no API cost.
- Admin configuration — New “Chat Widget” admin page controls title, welcome message, placeholder, color, position, max results, and editable system/user prompt templates with
{siteName},{excerpts},{question}placeholders. - Dedicated rate limiting — Separate per-IP (5/min) and global (30/min) limiters, independent from API and search limits. CORS restricted to configured
BASE_URL. - Source attribution — Every response includes a
sourcesSSE event listing the content pages whose excerpts were used, with titles and paths.
New Fork MCP Tools (8 added, 64 → 72 total)
list_forks— list all forks with status and page countcreate_fork— create a named fork workspaceget_fork— retrieve fork details including merge conflicts from last mergefork_page— add a page to a fork by content ID or pathremove_fork_page— remove a page from a forkmerge_fork— merge all fork changes into live content (admin only)archive_fork— archive a fork without mergingdelete_fork— permanently delete a fork and all its page copies
Security
- Prompt injection defense — Chat query text wrapped in
<user_question>XML delimiters before interpolation;</sequences escaped. Saved prompts validated to only allow known placeholders. - Configurable upload limit —
MaxUploadBytesin SiteConfig, settable via admin Configuration orupdate_site_config. Defaults to 1 MiB, enforced viahttp.MaxBytesReader. - API body size cap — All
/api/v1/endpoints enforce a 10 MiB request body limit, preventing memory exhaustion from oversized payloads. - Fly.io IP spoofing fix —
TrustFlyProxymode reads the unspoofableFly-Client-IPheader instead ofX-Forwarded-Forwhich can be forged by clients. - Session secret entropy — Production hard-fails on startup if
SESSION_SECRETis shorter than 32 characters. - Per-endpoint rate limiters — Dedicated limiters for regenerate (2/min), search-replace execute (10/min), bulk-update (5/min), export (5/min), reindex-embeddings (1/min).
- Rate limiter map pruning — Background goroutine prunes stale entries every 5 minutes, preventing unbounded memory growth.
Performance
- Admin template caching — Templates compiled once at startup via
sync.Once; previously re-parsed on every admin page request. - Content list pagination — Admin Content page loads 100 items per page with Previous/Next controls; previously loaded the full collection into memory, causing OOM crashes at scale.
- New content indexes —
{updated_at: -1}and compound{fork_id, deleted, updated_at}indexes fixSort exceeded memory limiterrors on Atlas free tier. - Search/replace streaming — All four search/replace handlers stream documents via MongoDB cursor instead of loading the full collection. Complete coverage, O(1) memory.
- Wikilink index cache — 60-second TTL cache with explicit invalidation on publish/title/path changes; eliminates O(n) full collection scans per page on bulk publish.
- Parallel hybrid search — Full-text and semantic search now run concurrently, halving latency when both sources are enabled.
- Parallel content regeneration —
RegenerateAllContentuses a 6-worker goroutine pool instead of sequential per-page processing.
v4.1.0 — Bug Fixes
Fixes redirect deletion not taking effect immediately due to browser caching.
Bug Fixes
- Redirect deletion now takes effect immediately — Redirects were served with
Cache-Control: max-age=3600, causing browsers to cache redirect responses for up to an hour. Deleting a redirect had no visible effect until the browser cache expired. Changed toCache-Control: no-storeso browsers never cache redirect responses.
v4.0.0 — Content Forks
Adds fork workspaces for safe page experimentation, bulk operation resilience improvements, and content search refinements.
Content Forks
- Fork workspaces — Create isolated staging workspaces where sets of page changes can be authored, previewed, and reviewed before going live. Only touched pages live in a fork (sparse model — unmodified pages fall through to live).
- Fork preview mode — Activate via a floating bar injected into the live site. A
lc_fork_previewcookie routes page requests through the fork, showing exactly how the site will look after merge. - Merge with conflict detection — Admins merge forks into live content. If a live page was edited after the fork was created, the conflict is recorded (fork wins). Newly created fork pages are inserted as live content on merge.
- “Fork to workspace” button — Available on any content edit page; opens the forks list with a one-click “Add to this fork” action.
- Fork exclusion from content list — Fork copies are invisible in the main admin content list and search results.
Performance & Resilience
- Coalescing background workers —
RegenerateIndexPagesandRebuildKeywordsnow use debounce channels: a bulk update of 25 items triggers one regeneration pass instead of 25 concurrent goroutines. Eliminates the goroutine explosion that caused server timeouts during large bulk operations.
Content Search
- Slug search mode — New search option alongside Title Only and Full Text. Searches slug and full_path fields, sorted alphabetically by slug.
- Homepage always first — The site index page (
/) is always pinned to position 0 in the content list and all search modes. - “/” query fix — Searching
/in Title or Full Text mode now correctly includes the homepage.
Dashboard & Bug Fixes
- Removed Collections KPI — The Collections stat card has been removed from the admin dashboard.
- Fork page unique index — Replaced the single-field
full_pathunique index with a compound{full_path, fork_id}unique index, allowing fork copies to share paths with their live counterparts without constraint violations.
v3.3.0 — Bulk Operation Performance
Significantly improves performance of all bulk and batch operations, with particular gains at scale (hundreds of content items).
Performance Improvements
- Scope filters pushed to MongoDB —
bulk_field_operation,scoped_search_replace_execute, andexport_contentnow push template, category, folder, and content_ids filters down to MongoDB instead of loading all content and filtering in Go. For a 600-item site scoped to 100 pages, this eliminates ~500 unnecessary document transfers. - Goroutine worker pool (10 concurrent) — All four bulk/search-replace execute handlers now process items concurrently with a pool of 10 workers instead of sequentially. On a 100-item batch this yields up to 8–10× faster wall time.
- Batch content fetch in bulk_update_content — Per-item
GetContentcalls replaced with a single$inquery. 100-item bulk update: 100 DB round-trips → 1 for the initial fetch. - content_versions index on content_id — Previously missing; every
UpdateContentcall triggered a full collection scan oncontent_versionsfor the version count. Now O(log n) per item. - template_name index on content — Enables MongoDB-level template scope filters to use an index scan instead of a full collection scan.
New Service Methods
- ListContentScoped — MongoDB-native scoped list with support for template_name, category, folder_path, and content_ids filters.
- GetContentByIDs — Batch-fetch multiple content items in one
$inquery, returning a map keyed by ID.
MCP Tool Fixes
- list_content include_data / include_fields — Fixed a bug where enriched field data was fetched correctly by the API but silently dropped before being returned to MCP callers.
- auto_republish on search & replace execute — New boolean parameter on
search_replace_executeandscoped_search_replace_execute. When true, pages that were published before the change are automatically re-published after replacement. - bulk_field_operation dry_run has_value — Dry-run results now report whether each matching page currently has a non-empty value for the target field.
v3.2.0 — Healthz Endpoint & DAU/MAU Analytics
Adds a structured health check endpoint following the VibeCtl Health Check Protocol, plus user activity tracking for DAU/MAU metrics surfaced in the health endpoint and admin dashboard.
/healthz Endpoint
- GET /healthz — Unauthenticated structured JSON status:
status,name,version,uptime,dependencies(live MongoDB ping), andkpis(DAU, MAU, pages created today) - HTTP 503 on unhealthy — Returns 503 when status is
unhealthy; 200 otherwise - Existing /health unchanged — Plain-text
OKendpoint for Fly.io TCP probes is preserved
Analytics & KPIs
- AnalyticsService — New service backed by
user_activitycollection. Activity recorded on admin login and API key auth via fire-and-forget goroutine (no request latency impact) - Unique-per-day deduplication — In-process
sync.Mapdedup prevents repeat DB writes for the same user on the same calendar day. Storage: at most one document per user per day with 90-day TTL auto-expiry - DAU / MAU — Daily Active Users (distinct today) and Monthly Active Users (distinct last 30 days) via aggregation pipeline
- Dashboard stat cards — Three new cards added: Daily Active Users, Monthly Active Users, Pages Created Today
v3.1.0 — Bulk Operations, Wiki-Like Markup & Security Hardening
First-class bulk content operations (eliminating N×1 API call patterns), a full wiki-like markup system for content authoring, configurable script policy, and comprehensive security fixes.
Bulk Content Operations
- bulk_update_content — Update up to 100 content items in a single MCP/API call with merge semantics. Supports
clear_fields,dry_run, and per-item success/error details - bulk_field_operation — Apply a single operation (clear, set, prepend, append, wrap) to a field across all matching pages. Scoped by template, folder, category, or IDs. Supports dry_run
- export_content — Export content items with full field data as structured JSON. Designed for the export → transform → bulk_update pipeline
- list_content with field data — New
include_dataandinclude_fieldsparameters return full template field values in list results, eliminating per-item get_content calls - clear_fields on update_content — Explicitly zero out fields, removing ambiguity about merge semantics
- dry_run validation — Validate update payloads without committing changes on both update_content and bulk_update_content
Regex Search & Replace
- All four search/replace tools now accept
"regex": truefor Go RE2 regular expression matching - Use
$1,$2for capture group references in replace strings - Input validation: 500-char pattern limit, max 20 capture groups, 10× expansion guard
Wiki-Like Markup System
- Wikilinks — Page Title, display, /path syntax in any content field. Resolves to <a> at page generation time; broken links render as broken-link spans
- Snippet includes — include:snippet-name embeds a named snippet inline in any content field. Depth limit 3, cycle detection
- Table of contents — Add {{.lc_toc}} in a template layout to auto-generate a <nav class="lc-toc"> from page headings
- Heading IDs — All h1–h6 tags automatically get id= attributes for deep-linking
- Markdown field type — Set a template field type to
markdownfor GFM rendering (tables, strikethrough, task lists, autolinks) - Inline #tag detection — Mentioning #tagname in any content field automatically tags the page for lc:query index pages
- get_backlinks MCP tool — Returns all published pages that wikilink or link to a given path. Useful before renaming or deleting pages
- Version history attribution — "By" column in version history shows the email of the editor who made each change
Configurable Script Policy
- New site config
markdown_script_policycontrols who may use raw <script> tags in content "all"(default) — all users may use scripts; fully backward-compatible"admin_only"— editor-authored content sanitized via bluemonday; admin content passes through unchanged"none"— all content sanitized regardless of author role- Configurable via admin Settings page or update_site_config MCP tool
Security Fixes
- Export authorization: export_content now requires authentication
- Regex DoS protection: pattern length cap (500 chars), capture group limit (20), expansion guard
- Snippet recursion guard: depth limit 3 with cycle detection
- Version history permissions: get_content_versions and get_content_version now enforce PermContentView
- Folder path scope bug: scoped search/replace with /blog no longer matches /blog-old
- Bulk field op limit: 500-page cap prevents unbounded database writes per request
- Wikilink href safety: resolved links not starting with / render as broken-link spans
- TOC HTML escaping: heading IDs in TOC anchors are properly HTML-escaped
- Rate limiter cleanup: background goroutine prunes stale entries every 10 minutes
v3.0.0 — Dynamic Index Pages: Tags, Snippets & lc:query
The most significant content modelling capability added since v1.0 — a first-class system for building dynamic, automatically-updated index pages.
Content Tagging
- Tags field on all content items — Any content item can carry zero or more freeform string labels, set in the admin editor or via
{"tags": [...]}in the REST API - Full API support —
GET /api/v1/content?tag=TAGNAMEfilters by tag;PUT /api/v1/content/{id}accepts a tags array - Tags are exact-match strings with preserved capitalization, indexed in MongoDB for efficient filtering
Snippets
- New
snippetscollection — Named HTML template fragments with Go template variable support - Admin UI at
/cm/snippets— Create, edit, and delete snippets with a live editor - REST API — Full CRUD at
/api/v1/snippets - Available variables —
{{.Title}},{{.FullPath}},{{.Slug}},{{.MetaDescription}},{{.PublishedAt}} - Rendered through Go’s
html/template— safe from XSS by default
lc:query Directives
- Embed live content queries in template layouts — Using HTML comment syntax:
<!-- lc:query filter="tag:X" snippet="name" --> - Processed at page generation time, replaced with rendered output of all matching published content items
- Filter options —
tag,category,template,folder - Sort options —
title:asc,title:desc,created_at:asc,created_at:desc - Multiple directives per template — each is an independent query
Automatic Cascade Regeneration
- Auto-regeneration — When tagged content is published or updated, all index pages whose templates contain
lc:querydirectives are automatically regenerated - Also triggers when a template layout or snippet is updated
New MCP Tools (5 added, 54 → 59 total)
list_snippets— list all snippetsget_snippet— retrieve a snippet by ID or namecreate_snippet— create a new named HTML snippetupdate_snippet— update a snippet’s name or HTMLdelete_snippet— delete a snippet
Security Fix
- XSS in
lc:querydefault fallback — When no snippet attribute was specified, title and path were concatenated without escaping. Fixed to usetemplate.HTMLEscapeString()
v2.6.0 — MCP Tool Improvements
Bug Fixes
get_themereturned empty strings —ThemeSettingsstruct was missingjsonstruct tags; all theme fields now serialize correctly via the REST API and MCPsearch_replace_executeresponse missing search/replace fields — Bothsearch_replace_executeandscoped_search_replace_executenow echo back thesearchandreplacestrings used
New MCP Feature: Rendered HTML in get_content
get_contentnow accepts aninclude_renderedboolean parameter- When
true, the response includes arendered_htmlfield containing the fully rendered page HTML (template + theme header/footer applied) - Works for both published and draft content — lets agents inspect exactly what visitors see without publishing
v2.5.0 — Security Hardening
- SSRF prevention —
upload_asset_from_urlblocks all private/reserved IP ranges (loopback, RFC1918, link-local, CGNAT, IPv6 ULA) before making any network request - ReDoS prevention — Full-text search runs under a 5-second context deadline, preventing pathological queries from pinning CPU
- Permission checks — Search-replace preview and reindex-embeddings endpoints now require admin-only permissions
- API rate limiting — Per-bearer-token sliding-window limiter: 300 requests per token per minute across the entire
/api/v1/subrouter - Asset serve_path whitelist — Upload paths restricted to
/assets/,/images/,/docs/,/media/, or/files/ - Trusted proxy IP extraction — Rate limiter uses configured trusted proxy settings, preventing IP spoofing via forged headers
- Database indexes — Compound index on the content collection for improved query performance under load
- Session secret validation — Server warns if secret is too short, fails hard in production if under 16 characters
v2.1.0 — Agentic API Improvements
Theme Reliability
- Theme CSS on startup —
static/css/theme-vars.cssis now regenerated from the database every time the server starts, preventing blank styles after a deploy or container restart
New Content Endpoints
- Update by path — Update content by URL path instead of MongoDB ID, useful when you know the page URL but not its ID
- Batch publish — Publish multiple content items in one call; pass an ID list or
publish_all_drafts: true - Content preview — Render a content item’s HTML without publishing; accepts optional title/data overrides to preview unsaved edits; returns
rendered_htmlandwarnings(missing required fields, unclosed tags, unresolved placeholders) - Rendered HTML in get_content —
include_rendered=truereturns the fully rendered page HTML alongside regular content data
New Asset Endpoints
- Upload from URL — Fetch a remote URL and store it as a LightCMS asset (HTTP/HTTPS only, 50 MB cap, MIME validation)
Theme Version Pinning
- Pin/unpin theme versions — Lock a theme version to protect it from auto-pruning; pinned versions are marked with
locked: truein version history
Scoped Search & Replace
- Targeted replacements — Run search-and-replace filtered by
content_ids,folder_path,template_name, and/orcategory— safer than a full site-wide replacement
New MCP Tools (13 added, 41 → 54 total)
update_content_by_path— update by URL path; merges data fieldspublish_multiple— batch publish by ID list or all drafts at oncepreview_content— render HTML without saving; supports field overridesscoped_search_replace_preview/scoped_search_replace_execute— folder/template/category-scoped search & replaceupload_asset_from_url— fetch remote file and store as assetpin_theme_version/unpin_theme_version— protect important theme milestones- Improved descriptions on existing tools with workflow guidance and examples
v2.0.1 — Configurable Search Ranking
- Database-stored ranking config — All search ranking parameters now stored in the database and editable from the admin panel at Tools → End User Search → Search Ranking
- Configurable fields — Title match boost, nav page boost, boosted template name substrings, template boost score, demoted path prefixes, demotion penalty score
- Safety clamping — Values clamped to −1.0…1.0 to prevent accidental misconfiguration
- Instant effect — Changes take effect immediately; in-memory cache invalidated on save
- Search API documentation — Expanded typeahead suggest API docs, full parameter tables, response schemas, and JavaScript examples in the admin Integration Guide and README
v2.0.0 — Multi-User RBAC & Smart Search
Multi-User Access Control
- Role-Based Access Control (RBAC) — Three roles (admin, editor, viewer) with granular permissions enforced on every admin UI page and REST API endpoint
- User Management — Admin-only panel at
/cm/usersfor creating users, assigning roles, disabling accounts, and resetting passwords - Email-based login — Authentication migrated from a single shared password to per-user email + password credentials
- Force password change — Temporary passwords prompt a mandatory change on first login
- Automatic migration — On first startup with an empty users collection, the existing admin password hash is carried over into a new admin user account
Audit Logging
- Persistent audit trail — All mutations logged with acting user, action, resource, and timestamp
- 365-day retention — Audit logs auto-expire via MongoDB TTL index
- Filterable UI at
/cm/audit— Filter by action type, resource, and date range - Async logging — LogAsync fire-and-forget pattern to avoid blocking request handlers
User-Scoped API Keys
- API keys now belong to a specific user and inherit that user’s permissions
- Admins can view and manage all keys; non-admins can only manage their own
- Keys created before v2.0 remain functional as system-level keys with full access
Smart Search Ranking
- Structural boost — Nav-linked pages (parsed from header HTML, cached 5 min) surface above other results
- Template-based ranking — Concept pages rank above generic body-only content
- Video deprioritisation — Pages under
/videos/rank below all other content types - Typeahead suggestions — Same structural ranking applied to prefix-match suggestions
- Ranking priority: title+nav > title-only > nav-linked > concept pages > body-only > video transcripts
Bug Fixes
- Fixed
/cm/auditpage crash caused by subtract/add template functions receiving mismatched integer types - Made arithmetic template functions type-flexible via
interface{}dispatch
v1.4.0 — End-User Search API
- Full-text search (
/api/search?q=...) — Regex-based exact matching across all published content - Semantic vector search — Voyage AI embeddings stored in MongoDB Atlas;
$vectorSearchpipeline for similarity queries - Hybrid mode — Reciprocal rank fusion (RRF, k=60) merges full-text and semantic results into a single ranked list
- Title boosting — Results where the query appears in the page title float above body-only matches
- Graceful degradation — Works without a Voyage API key (full-text only); automatically enables semantic search when configured
- Rate limiting — Per-IP (10 req/min) and global (100 req/min) limits with DDoS protection
- Embedding pipeline — Background batch generation with progress tracking in the admin panel
- Typeahead suggestions —
/api/search/suggestendpoint for prefix-matching page titles and extracted keywords - WARP proxy for Voyage API calls on Fly.io to avoid IP-based rate limiting
- Upgraded embedding model from voyage-3-lite to voyage-4-lite
- Fixed SVG assets not displaying when uploaded with
/assetspath prefix - Expanded upload allowlist to include CSS, JS, JSON, and other text-based web assets
v1.2.0 — OAuth 2.1 & HTTP MCP Transport
- OAuth 2.1 authorization server — Full authorization code flow with PKCE (S256), dynamic client registration (RFC 7591), token rotation, and revocation (RFC 7009)
- Remote MCP clients — HTTP streamable MCP endpoint at
/mcp— connects Cowork, Claude Desktop, and any MCP-compatible app without embedding credentials - Discovery endpoints —
/.well-known/oauth-authorization-server(RFC 8414) and/.well-known/oauth-protected-resource(RFC 9728) for automatic client setup - Dynamic MCP server card —
/.well-known/mcp/server-card.jsonwith full tool schemas, served live from the running server - Smithery registry support — smithery.yaml and packaging config for registry publication
- Test suite: 82% → 86% coverage with CI via GitHub Actions and Codecov integration
- Loading state feedback on OAuth authorize buttons
v1.1.0 — REST API, CLI Tool & API Keys
- REST API at
/api/v1/— Full JSON API for all content management operations (content, templates, assets, theme, config, redirects, folders, collections) - API key authentication —
lc_-prefixed keys stored as SHA-256 hashes; created and managed in the admin panel - CLI tool (
cmd/cli) — Command-line interface wrapping the REST API for scripting and CI/CD workflows - MCP refactor — MCP tools now use the REST API client rather than direct DB access
- Partial update support on all PUT endpoints (send only changed fields)
v1.0.0 — Initial Release
- Content management — Create, edit, publish, and delete content using customizable templates
- Template system — Define reusable page structures with typed fields; HTML layout with
{{.field_name}}placeholders - Static page generation — Published content rendered to
content/generated/for fast, zero-runtime serving - Content versioning — Automatic version snapshots on every update; revert to any prior version
- Soft delete — Deleted content recoverable from the admin panel
- Content collections — Auto-generated paginated listing pages filtered by category
- MCP server (stdio) — 43 tools for managing the entire site through AI agents
- Theme customization — Colors, fonts, border radius, custom CSS; header/footer HTML injection with versioning
- Asset management — Upload, organize, and serve images, documents, and other files
- URL redirects — 301/302 rules managed from the admin panel
- Rich text editor — TinyMCE integration for visual editing
- Search & replace — Site-wide text replacement with preview before execution
- Security — CSRF protection, bcrypt passwords (cost 12), session cookies (SameSite=Strict), file upload validation, login rate limiting
- Fly.io deployment — fly.toml and Dockerfile for one-command production deploy
MIT License · Copyright 2026 Metavert LLC