Plugins without the plugin jungle: a whole blog with comments in one sandboxed script
I built ForgeCMS because I was tired of WordPress plugins. Every site I ran needed a dozen of them, each with its own updates, its own security holes and, more and more often, its own subscription. When my hosting provid
I built ForgeCMS because I was tired of WordPress plugins. Every site I ran needed a dozen of them, each with its own updates, its own security holes and, more and more often, its own subscription. When my hosting provider simply removed my WordPress sites, I decided my next CMS would have no plugin jungle at all.
But a CMS without any way to extend it is a dead end too. Somebody always needs a guestbook, a poll, a price calculator. So the question was: how do you get plugins without getting the jungle back?
This week the answer went live.
A plugin is two files in your Git repo
ForgeCMS sites are Markdown and small SML files in a Git repo. A plugin is just two more files next to the pages:
plugins/guestbook/plugin.sml what the plugin is and which permissions it wants
plugins/guestbook/plugin.sms the script
The script is written in SMS, a small Kotlin-like language from our Forge project. It has one job: build a piece of the page.
fun render(props, ctx) {
var out = "Heading { level: 2 text: " + sml.quote("Guestbook") + " }\n"
for (e in store.list("entries")) {
out = out + "Text { value: " + sml.quote(e["name"] + ": " + e["message"]) + " }\n"
}
return out
}
You put it on a page with one line, Plugin { name: "guestbook" }, push, and reload. No build, no deploy, no restart. ForgeCMS notices the changed script and loads it again.
The sandbox is the point
A WordPress plugin is PHP with all the rights of your server. An SMS plugin only has the functions ForgeCMS hands to it:
- the language itself (strings, lists, maps, dates),
-
store.*: its own small records on the server, as plain files (no database), -
content.*: read the text files of the content repo, never the server config, -
mail.admins(...): a mail to the plugin's admins, nobody else.
No file system, no network, no programs. Each call gets a budget of one million steps, 250 ms and 32 MB; an endless loop is stopped after about 10 ms of work.
And the important bit: the plugin can only ask for permissions. The content repo is not trusted, so only app.sml on the server grants them:
Plugins {
Plugin { name: "blog" allow: "content store mail" path: "/blog" admins: "[email protected]" }
}
A compromised repo or a pull request cannot turn on a new plugin, give one mail rights or make somebody an admin.
What comes back from the script is SML, not HTML, and ForgeCMS cleans it: only layout elements, safe links, Markdown without raw HTML. A visitor who types "} HTML { ... } into a form just sees that text.
The test: a whole blog
A guestbook proves little. So I asked: could the blog itself be a plugin?
It can. The blog plugin is about 600 lines of SMS and does:
- a list of posts with paging, and "the latest three" for a start page
- a page per post: Markdown from the repo, preview image for link sharing, older/newer links
- an Atom feed
- drafts and scheduled posts
- comments: moderated by default. The admin gets a mail with a link, logs in with their email address, and approves or deletes right under the post
- German, English and Spanish
It reads the same blog.sml format as the built-in blog module, so my travel diary would run on it unchanged. On those 23 real posts a page takes about 2 ms.
Writing it was also the real test of the plugin API. It needed things the guestbook never did: its own addresses below /blog, a feed that is not HTML, a page title and preview image per post, an admin login, mail. All of that is now in the API, documented in one text: the plugin spec.
Try it: crowdware.info/blog-plugin-demo. Leave a comment; I get the mail and approve it.
The AI writes the plugin
This is the part I care most about. You don't need to know SMS. Give the AI the spec (forgecms --plugin-spec prints it) and say what you want:
"A plugin for my yoga site: a list of this week's classes with a sign-up form, at most 12 people per class, mail me when someone signs up."
The AI writes the two files, you push them, reload the page, done. Want it different? Tell the AI, push again.
Free software, made to be changed
Both plugins, the guestbook and the blog, are GPLv3 in the ForgeCMS repo. Copy one into plugins/ of your site and make it yours. Built something others could use? Send a pull request on Codeberg.
- Demos: guestbook ยท blog with comments
- Code: examples/plugins
- Spec: SPEC.md
- ForgeCMS for developers: crowdware.info/forgecms/developers
What plugin would you write first?
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes โ full credit and traffic to the original publisher.