Documentation

Ship the site. Not the stack.

Forma is a portable PHP + SQLite CMS — dark admin, Markdown, SEO, one-URL AI connections with rollback, and versioned site packages. This page is assembled with reusable snippets: [[​site-head]], [[​site-header]], [[​site-footer]].

PHP 8.1+ SQLite one file AI OAuth + MCP SEO built-in

Install

No MySQL. No Composer. Drop Forma on a host with PHP 8.1+, pdo_sqlite, and rewrite support.

Source on GitHub   Latest release

git clone https://github.com/Alta-forma/forma-cms.git
cd forma-cms
chmod -R 775 database uploads feeds
php -S localhost:8787 router.php

Open /admin, log in with admin / admin, and change them immediately under Settings → Access.

DreamHost: point the document root at the folder that contains index.php. Keep database/ and uploads/ when you redeploy code. Use Settings → Server to write .htaccess (Authorization header passthrough is included — DreamHost FastCGI strips it otherwise). Full notes: the DEPLOY.md in the repo.

Update

After Forma 0.2.0, existing sites update in the admin: Settings → Forma core → Update Forma core. That installs the latest GitHub Release only — never main.

  • Does not touch database/, uploads/, feeds/, fallback/, .htaccess, or license secrets
  • Takes an app-file backup first; Rollback is on the same screen
  • Download new installs from Releases, not “Code → Download ZIP”

AltaForma publishes with ./tools/release.sh after bumping version.php. Checklist: RELEASE.md.

Admin

The admin is htmx + CodeMirror — sections load into the main pane without a SPA rebuild.

  • Pages — HTML/Twig or Markdown, META block for slug + SEO
  • Blog — Markdown posts, RSS/JSON feeds
  • Podcasts — episodes + iTunes-compatible feed (license unlock)
  • Uploads — media library; image fields use Browse / Upload pickers
  • Snippets — reusable HTML via shortcodes
  • Settings — site, SEO, server, Forma core, Access, backup

Pages & blog

Full HTML documents are served as-is (great for marketing pages). Fragments get a minimal shell. Blog posts are Markdown with publish dates — unpublished posts 404 on purpose.

META block

<!--META
slug: /docs
title: Docs
seo_title: Forma Docs
seo_description: …
-->

Snippets

This docs chrome is snippet-driven so you can reuse nav and footer everywhere:

  • [[​site-head]] — fonts + shared CSS tokens
  • [[​site-header]] — sticky nav / menu
  • [[​site-footer]] — footer links

Edit them under Admin → Snippets. Twig is optional inside snippet bodies if you need site config variables.

SEO

Settings → SEO covers sitewide defaults; pages/posts override per document.

  • Auto /robots.txt and /sitemap.xml (including images)
  • Open Graph / Twitter, favicon, default share image
  • JSON-LD (Person / Organization / LocalBusiness)
  • Redirects manager
  • Health score for missing titles, descriptions, images

Podcast

Forma itself is free. Podcast RSS (iTunes-compatible show + episodes) is a $39 one-time unlock.

Buy Forma Podcast — $39. After Stripe emails the key, paste it under Settings → General. Local/dev: FX-DEV-LOCAL.

AI connectors & Agent API

Settings → Access has three clear ways in: an admin login for you, OAuth for compatible AI chatbots, and scoped Bearer API keys for Cursor, scripts, and ChatGPT Actions.

Grok, ChatGPT, Claude, Perplexity

For a remote MCP connector, paste one URL. Forma publishes OAuth discovery, registers the client, and asks you to sign in and approve Site editor access — no token copying.

https://your-site.com/api/v1/mcp

The chatbot grant can read and update content, upload media, update public identity and SEO, and use rollback. It cannot delete, change accounts, import backups, read backups, alter security, or update Forma core. Access tokens last one hour and renew through rotating refresh tokens.

Cursor, scripts, and Actions

Create an API key under Settings → Access when the client cannot do browser-based OAuth. Discover the full API map first:

curl -H "Authorization: Bearer fx_…" \
  https://your-site.com/api/v1/help

DreamHost-safe alternate header: X-Forma-Token. Separate read, write, delete, media, settings, backup, podcast, and rollback scopes keep each key as narrow as the job allows.

One last-known-good site

Before the first Agent API or MCP write, Forma protects one rollback point. Settings → Access shows Put it back while edits are pending. After checking the public site, This looks good moves the safe point forward.

Important: rollback is one safety point, not revision history. New orphan uploads can remain after restore. Never mark a site good until a human has checked the public result.

Site packages

Settings → Backup → Download site package, or GET /api/v1/export/site.

manifest.json     # format_version + schema_version
data.json         # portable content
database/forma.db # SQLite snapshot
uploads/          # media

Future Forma versions migrate using schema_version. Packages newer than the running app are rejected.

Remote & Cursor MCP

Subscription chatbots use the hosted Streamable HTTP endpoint at /api/v1/mcp. Paste the URL and let OAuth handle the credential. The remote tool list is intentionally limited to the non-destructive Site editor surface.

Cursor can use the local MCP wrapper with a scoped API key. Start with formax_help, then pages, posts, snippets, media, SEO, and rollback tools.

export FORMA_X_URL=https://your-site.com
export FORMA_X_TOKEN=fx_…
php tools/formax.php help
php tools/formax.php site

ChatGPT Custom GPT Actions use the public /api/v1/openapi.json contract with a Bearer API key when remote MCP is unavailable.

Screenshots

Live Forma admin — Blog, Podcast, Uploads, Snippets, Cache, and Server.

Forma admin Blog editor Forma admin new podcast episode Forma admin Uploads Forma admin Snippets search-ui Forma Settings Cache Forma Settings Server