JSON Communication Protocol
Plugins communicate with Accent CMS via JSON strings. This keeps the interface simple and language-agnostic. The sections below show the exact input and output shape for each kind of plugin function.
Hook Input/Output
// Input to on_page_load / on_render { "content": "# Hello World\n\nThis is content.", "page_path": "/blog/my-post", "config": { "theme": "monokai", "line_numbers": true } } // Output from hook { "content": "<h1>Hello World</h1><p>This is content.</p>", "error": null }
Filter Input/Output
// Input to filter function { "value": "fn main() {}", "args": ["rust"], "config": { "theme": "monokai" } } // Output from filter { "value": "<pre class=\"highlight\"><code>...</code></pre>", "error": null }
Route Handler Input/Output
// Input to route handler { "method": "POST", "path": "/api/highlight", "headers": { "content-type": "application/json" }, "body": "{\"code\": \"...\", \"lang\": \"rust\"}" } // Output from route handler { "status": 200, "headers": { "content-type": "text/html" }, "body": "<pre>...</pre>" }
Media Discover Input/Output
// Input to on_media_discover { "file_path": "/content-media/blog/post/hero.jpg", "mime_type": "image/jpeg", "config": { "extract_exif": true } } // Output from on_media_discover { "metadata": { "blurhash": "LKO2?U%2Tw=w", "exif": { "camera": "Canon EOS R5", "iso": 400, "aperture": "f/2.8" } }, "error": null }
The metadata map is merged into the media asset and becomes available in templates via {{ asset.metadata.blurhash }} or {{ asset.metadata.exif.camera }}.
metadata.thumbnail_url — reserved key
Setting metadata.thumbnail_url to a string URL has special meaning: Accent mirrors it onto the asset’s typed thumbnail_url field after plugin hooks finish (when no Layer 1 convention thumbnail or Layer 2 frontmatter override has already populated it). The pdf_card() template function and the [pdf] shortcode then use the URL directly without going through the ?thumb query parameter. This is the supported path for plugins that produce real raster previews from PDFs (or any other asset).
// On a PDF that the plugin can preview: { "metadata": { "thumbnail_url": "/plugin-cache/report-page1.jpg" } }
The bridge runs in both serve mode and accent build. Author-provided sources (Layer 1 / Layer 2) outrank plugin-set thumbnails; non-string and empty-string values are ignored.
Media Process Input/Output
// Input to on_media_process { "image_data": "base64-encoded-image-bytes...", "content_type": "image/webp", "source_path": "/blog/post/hero.jpg", "width": 800, "height": 600, "config": { "watermark": true } } // Output from on_media_process { "image_data": "base64-encoded-modified-bytes...", "content_type": "image/webp", "metadata": { "watermarked": true }, "error": null }
If image_data is null in the output, the original processed bytes are preserved. If content_type is null, the original content type is preserved. This allows plugins to add metadata without touching the image bytes.
If a plugin returns an error string instead of null, the error is logged and the original content is preserved (hooks) or an error response is returned (routes).