Skip to content

Developer guide

Hussein Jarrar edited this page Sep 12, 2026 · 2 revisions

How Radd is built, and how to extend it. This guide is for a developer who writes a plugin, an editor extension or an automation node.

The design in one paragraph

Radd is a kernel and a set of plugins. The kernel holds mechanism only: the plugin contract, the contribution registries, the loader, and the pure contribution specifications. It imports nothing from any plugin. Every feature is a plugin, including the 52 that ship with the product, and the server is assembled from configuration. A plugin contributes entities, permissions, events, routes, navigation, MCP tools and query fields through declarations that the kernel reads blind.

Read in this order

Page Covers
Architecture: the kernel and plugins The plugin contract, the registries, the loader, EntitySpec
Events and consumers Declaring, emitting and consuming an event
Permissions and access control Permission atoms, scope, and the access-grant framework
Write a backend plugin A complete tutorial, from empty directory to loaded plugin
Write a plugin user interface Module federation, the SDK, slots and theme tokens
Write a page editor extension A radd: fence as a real editor node
Write an automation node Triggers, conditions and actions
The query language for developers SLQ, its two dialects, and adding a field
The REST API and authentication Credentials, error shapes and route rules
The MCP server Contributing a tool, and the per-caller catalog
Develop, test and deploy Running it, testing it, migrating it, shipping it

Three rules that explain most of the code

A plugin talks to another plugin through its public service.py, its events, and its declared extension points. It never reaches into another plugin's tables. One exception is measured and enforced: the models of auth, projects, items, workflow, teams and fields are the de-facto spine and may be imported for reads. Writes always go through the owner's service.

Every cross-plugin import is declared. Use depends_on when the target must load first, and weak_depends for a deferred reverse reach. A test refuses an undeclared edge.

A value that names a behaviour, a state or a type is an enum member, never a string literal. Tunables live in config.py.

Pages


Mirrored from project.radd-hq.com on 2026-09-12. Documentation is written there; this copy is regenerated by scripts/publish_wiki.py and hand edits do not survive it.

Clone this wiki locally