Every type, rule, tool and option
Tables to look things up in. The guide explains how to use them.
Element types
The C4 metamodel has the first eight. The Radical metamodel has all of them, lets a Software System sit inside a Domain, and adds the rest. Types of the Radical layers sit at the root, in a system, in a domain or in a group unless the table says otherwise. Every type has a name, a description and a parent.
C4
| Type | What it is | Lives in | Fields |
|---|---|---|---|
| Person | Someone who uses or runs the system: a customer, an operator, another team. | Root, group. Never inside a system. | External |
| Software System | Something that delivers value and is owned by one team: yours, or one you depend on. | Root, group, system; in Radical also a domain, as the bounded context that realises it. | External |
| Container | Something that runs or stores data and is deployed on its own: a service, a worker, a mobile app. | System, or a group inside one. | Technology, External |
| Database | A container that stores data and never starts an interaction. | System, or a group inside one. | Technology, External |
| Web App | A container that is a browser front end; it may hold components. | System, or a group inside one. | Technology, External |
| Queue | A container that carries messages between containers. | System, or a group inside one. | Technology, External |
| Component | A part of a container behind a clear interface: a controller, an adapter. | Container, web app, or a group inside one. Never straight in a system. | Technology, External |
| Group | A labelled boundary with no meaning of its own: a team, a layer, a zone. No relation starts or ends at a group. | Root, group, system. | — |
Domain
| Type | What it is | Lives in | Fields |
|---|---|---|---|
| Domain | A part of the problem space in the language of the business: Payments. A domain in a domain is a subdomain. | Root, group, domain. | Kind (core, supporting, generic), Vision |
| Entity | A thing with an identity over time: an order, a reservation. An aggregate root is a consistency boundary; an entity is part of exactly one root. | Root, domain, group. | Kind (aggregate root, entity) |
Requirements
| Type | What it is | Fields |
|---|---|---|
| Need | Raw stakeholder input kept verbatim: a brief, a user story, a regulation. No status; nothing satisfies or verifies it. | Kind, Source; the text is the description |
| Requirement | One thing the system shall do, as an EARS sentence. Its subject is the first element that satisfies it. | EARS type (ubiquitous, event-driven, state-driven, unwanted behaviour, optional, complex), Trigger, Precondition or While in state, Condition, Feature, Action, Rationale |
| Scenario | An acceptance example in Gherkin. | Given, When, Then, Extra steps, Tests (one file › title per line) |
States
| Type | What it is | Lives in | Fields |
|---|---|---|---|
| State Machine | The lifecycle of one entity, drawn as a frame that holds its states. | Root, system, domain, group. | — |
| State | A situation the entity can be in. A state with states is compound. | Machine, state. | Kind (normal, parallel, final), Entry, Exit, Do |
| Pseudostate | A point the machine passes through: initial, shallow or deep history, choice. | Machine, state. | Kind |
| Event | Something that happens and can trigger a transition. | Root, machine, system, domain, group. | Source (external, internal, timer), Payload |
Process
| Type | What it is | Lives in | Fields |
|---|---|---|---|
| Process | A procedure made of steps. | Root, system, domain, group. | Children run (sequence, choice, concurrent) |
| Step | One part of a process. | Process, step. | Order, Repeat (1, 0..1, 1..n, 0..n), Condition, Children run |
UX and governance
| Type | What it is | Fields |
|---|---|---|
| Mockup | One screen of the product, with an optional low-fi wireframe (sanitised SVG). | Screen / route, Design link, Wireframe |
| ADR | An architecture decision record in the Nygard / MADR shape. A new one starts proposed with today's date. | Status (proposed, accepted, deprecated, superseded), Date, Context, Decision, Consequences, Alternatives considered, Concern |
| Fitness Function | An automated check that the architecture keeps a property it was designed for. | Category (structural, operational, process, holistic), Threshold / success criteria, Tests |
| Blueprint | A curated reference architecture as the Hub once shipped them. Not in the palette; models that hold one keep it. | Status, Domain / context, Rationale |
Relation types
Each relation has a direction: read it as a sentence from source to target. Studio picks the type the pair of ends allows; where two fit (entity → entity, domain → domain) it asks which.
C4
| Relation | From → to | Fields | Meaning |
|---|---|---|---|
| Interacts | Person → system, container, web app, component System → person, system, container, database, web app, queue, component Container, Web App → person, system, container, database, web app, queue Component → component, container, web app, database, queue, system Queue → container, web app, component | Technology | The source calls, uses, sends to or delivers to the target. Draw it from the initiator. A database never initiates; nothing touches a group. |
Domain
| Relation | From → to | Fields | Meaning |
|---|---|---|---|
| Realises | System, container → domain System, container, component, web app → entity | — | The bounded context that implements the domain; the element that owns the entity's data. |
| Part of | Entity → entity | — | A part of an aggregate points to its root. |
| References | Entity → entity | Cardinality (one, many) | One aggregate refers to another by id. |
| Depends on | Domain → domain | — | The source needs the target to do its work. |
| Partnership | Domain → domain | Pattern (partnership, shared kernel, customer–supplier, conformist, anti-corruption layer, open host service, published language, separate ways) | How the two teams' models meet. |
Traceability
| Relation | From → to | Fields | Meaning |
|---|---|---|---|
| Derives from | Requirement → need Requirement → requirement Need → need | — | The requirement turns that input into a shall-statement; decomposition; a need inside a broader one. Nothing else may point at a need. |
| Satisfies | C4 element, domain, entity, state machine, process → requirement | Note | This element is what makes the requirement true. The first one is the subject of the EARS sentence. |
| Verifies | Scenario → requirement, state machine, process | — | The scenario is the acceptance test for it. |
| Traces to | Requirement → ADR, fitness function | — | The decision the requirement led to, or the check that keeps it. |
Behaviour
| Relation | From → to | Fields | Meaning |
|---|---|---|---|
| Lifecycle of | State machine → entity | — | One machine per entity. |
| Implements | System, container, component, web app → state machine Fitness function → ADR | — | This element runs the machine; this check verifies that the decision still holds. |
| Transition | State, pseudostate → state, pseudostate, within one machine | Event, Guard, Actions, Raises, Kind (external, internal) | Labelled event [guard] / actions ^raised. No event means a completion transition. |
| Emits | Person, system, container, component, web app, queue, state machine, state → event | On (entry, exit, do) for a state | This element raises the event. |
| Performed by | Step → person, system, container, component, web app | — | Who does the step. |
UX and governance
| Relation | From → to | Fields | Meaning |
|---|---|---|---|
| Illustrates | Mockup → requirement, scenario, state | — | The screen shows this being met, or what the user sees in this state. |
| Presented by | Mockup → web app, container, component, system | — | The part of the architecture that renders the screen. |
| Navigates to | Mockup → mockup | Trigger | One step of a screen flow. |
| Constrains | ADR, fitness function, requirement → person, system, domain, container, component, database, web app, queue | Note | The decision, check or requirement applies to that element. An agent reads this before it changes the element. |
| Supersedes | ADR → ADR | — | The newer decision replaces the older one. |
Viewpoints
The Radical metamodel ships these twenty-five. The C4 metamodel ships the first six. Per element marks a viewpoint that makes a group with a view of each element of its type.
| Group | Viewpoint | View type | What it shows |
|---|---|---|---|
| C4 | System context | Structure | The people and systems, with every relation between them |
| Containers | Structure | The containers inside the systems | |
| Components | Structure | The components inside the containers | |
| Containers of a system | Structure, per element | One system, its containers and what they are related to: C4's container diagram | |
| Components of a container | Structure, per element | One container, its components and what they are related to | |
| Container dependencies | Matrix | Containers, web apps, databases and queues | |
| Domain | Domain map | Structure | Domains and how they depend on and partner with each other |
| Domain model | Structure | Entities, what they are part of and reference | |
| Entities of a domain | Structure, per element | One domain, its entities and the entities they reference | |
| Domain realisation | Table | Domains, their entities and what realises each | |
| Requirements | Traceability | Table | Needs, the requirements refined from each, the scenarios that verify those |
| Requirement coverage | Table | Requirements, what satisfies and verifies each | |
| Requirement gaps | Table | Requirements no scenario verifies or nothing satisfies | |
| Responsibilities | Table | Systems, containers and components with the requirements they satisfy | |
| Specification | Wiki | Needs, their requirements and the scenarios and screens for each | |
| Decisions | Decisions | Table | ADRs, the fitness functions that check each and what it constrains |
| Decision log | Wiki | ADRs, newest first, each with the ones it supersedes | |
| Fitness functions | Table | By category, with what each checks and constrains | |
| UX | Screen flow | Structure | The screens and how users move between them |
| Screens | Table | The screens with what they illustrate and what presents them | |
| States | Entity lifecycles | Table | Entities with a state machine, what implements and verifies it |
| State machine | Structure, per element | One machine with its states, events and transitions | |
| Event catalogue | Table | The events and what emits each | |
| Process | Process (Warnier) | Warnier | The processes and their steps as Warnier–Orr diagrams |
| Process | Structure, per element | One process and its steps |
Summary templates
Summary in tables on a node type is a template of tokens. A part in [ ] is left out when a token in it is empty; the template's own text may use Markdown. Left empty, the built-in template applies, else the description's first sentence.
| Token | What it gives |
|---|---|
{key} | A property; also {label}, {description}, {technology}, {type} |
{ears} | A requirement's whole EARS sentence |
{obligation} · {condition} | Who shall do what; the when / while / if / where it holds under |
{transitions} | Where a state machine goes from a state or on an event |
{out:type} · {in:type} | The elements linked by relations of a type, out or in |
{key.sentence} · {key.phrase} | The first sentence; the first phrase |
{key.cap} · {key.bold} | Capitalised; bold |
{a|b} | The first of them that has a value |
Built-in templates: [{obligation.bold}][ — {condition}] for a requirement, [{then.phrase.cap.bold}][ — when {when}] for a scenario, [{status.cap.bold}: ]{decision.sentence} for an ADR.
Rules & checks
The metamodel is enforced in three rings: what Studio refuses at once, what the Validation list and get_issues list as issues, and what only radical check and the Inspector report.
Refused at once
- Placing or moving an element where its type may not sit, or at the root when it needs a parent.
- One more element of a type that has reached its maximum.
- A relation type that does not join its two ends, or a pair no relation type allows.
- Changing an element's type when one of its relations would then not be allowed.
- Moving a group where something it holds would have no place; moving an element into itself.
- A transition out of a final state, or into an initial pseudostate.
The same refusals reach the AI assistant, Radical Forge and the MCP server as messages they can act on.
Listed as issues
| Area | Issues |
|---|---|
| Any metamodel | An unknown type, a misplaced element, a relation to an element that is gone or between types no relation joins, a reference that points at nothing or the wrong type, an empty required field, too few or too many elements of a type; in custom metamodels, two properties of a type with one key. |
| Domain model | An aggregate root that is part of something; a part of something that is not a root; an entity that belongs to no aggregate or to two. |
| State machines | A machine with no entity, or an entity with two machines; no initial pseudostate, or more than one; an initial pseudostate without exactly one outgoing transition; a parallel state with fewer than two regions; a final state with children or outgoing transitions; a transition that leaves its machine; two unguarded transitions from one state on one event; a state the initial state cannot reach. |
Checked by radical check
Warnings unless check.json says otherwise; radical check --list-rules lists them with their ids.
| Area | Rules |
|---|---|
| Requirements | A requirement without the clauses its EARS type needs; one no scenario verifies; one nothing satisfies; one that derives from nothing; a need no requirement derives from; a scenario that verifies nothing. |
| Concerns | concern-unaddressed: a concern a pack finds in the model that no accepted ADR marked with it covers. concern-unbound: an accepted ADR marked with a concern that constrains no element. |
| Decisions | An accepted ADR no fitness function implements; one without date, context, decision or consequences; a superseded status and Supersedes links that disagree; a fitness function that implements no ADR and constrains nothing, or has no threshold. |
| Tests | A scenario or fitness function that names no test. With reports: a named test that failed or is missing (errors), was skipped, or whose file did not run; with an include, tests the model does not name (test-unbound). |
| The folder | A missing radical.md, a JSON file that does not parse, git conflict markers, a node file without id or type, two files with one id (errors); views, sequences or slides that point at something gone. |
| Goals | goal-unmet: a metric below the share check.json asks for (requirements with a scenario, accepted ADRs with a fitness function, requirements verified, scenarios passing, …). |
radical check
Checks a Markdown folder: the folder's files, the metamodel rules and the completeness rules above. It never changes the model. Run the published package, or build it from a clone (see Install & build).
npx -y @radicaltools/cli check path/to/my-model --report reports
| Option | What it does |
|---|---|
[folder] | The model folder. Default: the working directory. |
--config <file> | Rule settings. Default: check.json in the model folder. |
--format text|json|github | Plain text (default), JSON, or GitHub Actions annotations. |
--report <path> | A test report (Vitest or Jest JSON, Playwright JSON, JUnit XML) or a directory of them; repeat for more. The test cases read are kept in .radical/test-results.json for the Inspector. A report with no test case stops the check with status 2. |
--evidence <file> | With --report: writes what the reports say about each scenario, fitness function, requirement and ADR as JSON. |
--ratchet | Lowers each max in the config to the count found now and writes the config back. Never raises one. |
--verbose | Lists every warning, not the first five of each rule. |
--list-rules | Lists the rules, their default severity, and the metrics goals can set. |
radical --version | Prints the version, with the commit when the build is not a release (0.3.0+1a2b3c4). |
Exit status: 0 no errors (warnings allowed), 1 errors, 2 the check could not run.
check.json
rules sets a rule by its id, or one kind of metamodel issue by metamodel/<code>, to error, warning or off. With max, up to that many findings pass as warnings and one more fails the check, so an existing model can adopt a rule before every gap is closed. goals sets the least share of a metric, in percent; a metric below its goal is goal-unmet, an error unless set otherwise.
{
"rules": {
"adr-incomplete": "off",
"requirement-without-scenario": { "severity": "error", "max": 104 }
},
"goals": {
"requirements-with-scenario": { "min": 85 },
"requirements-verified": { "min": 80 }
}
}
The Inspector's Settings tab edits the same file.
Changes on branch
radical diff <folder> prints the elements and relations added, removed and changed since the branch left main, with old and new values. Views and layout are left out. --since <ref> compares with another commit, tag or branch.
The base is the model at git merge-base HEAD origin/main, saved to .radical/base.json. Studio reads the file every few seconds and compares the model with it as you edit. Only the command line and the MCP server save it:
| Saves the base | Through |
|---|---|
| A checkout or switch of branch | the post-checkout hook |
| A commit, amended too | the post-commit hook |
| A pull that merges or fast-forwards, a merge | the post-merge hook |
A rebase, git pull --rebase, an amend | the post-rewrite hook |
An agent's get_changes without since | the MCP server |
| By hand | radical diff <folder> --save-base |
radical hooks install <folder>adds the four hooks. A fetch, a reset or a stash runs no hook.- Committing keeps the base, so the list holds the whole branch's work. After the pull request is merged, switch to
mainand pull: the list empties. - To see only what is not committed yet:
radical diff <folder> --save-base --since HEAD. - A folder outside git has no base from git. A Radical Forge run on such a folder saves the model before it as the base; the next run replaces it.
- A base older than a day is marked in the Inspector with the commands that save it again.
MCP server
Runs locally over stdio, bound to one Markdown folder. Node.js 20.11 or newer.
npx -y @radicaltools/mcp --folder /absolute/path/to/my-model # waits for MCP messages on stdin
radical-mcp --version
Claude Desktop: add it under mcpServers in ~/Library/Application Support/Claude/claude_desktop_config.json (Windows: %APPDATA%\Claude\claude_desktop_config.json) and restart the app. Give the full path to node, because the app does not see your shell's PATH.
{
"mcpServers": {
"radical-folder": {
"command": "/usr/local/bin/node",
"args": ["/path/to/radical.tools/apps/mcp/dist/index.js", "--folder", "/path/to/my-model"]
}
}
}
--metamodel radical|c4picks the metamodel of a new folder (defaultradical). A folder with other files and noradical.mdis refused.- Studio warns once when the server's version differs from its own; update the older one.
- Not supported: single
.radicalfiles, driving Studio's canvas, loading a milestone over the model, clearing the model, remote HTTP connections.
Tools
| Group | Tools |
|---|---|
| Read | get_model_summary (counts, views, sequences, milestones, the modelling rules and the metamodel rules) · get_issues · search_model (LIST NODES WHERE …, GET NEIGHBORS, LIST SEQUENCES) · get_selection · get_changes |
| Elements & relations | add_node, update_node, delete_node, move_node · add_relation, update_relation, delete_relation |
| Views | create_view, update_view, set_view_nodes, order_views, delete_view · smart_layout · align_nodes, grid_nodes, remove_alignment |
| Sequences & slides | create_sequence, update_sequence, delete_sequence · create_presentation, update_presentation, delete_presentation (a slide shows a view or zooms onto elements with focus, from the model or a milestone) |
| Milestones | list_milestones, create_milestone, update_milestone, delete_milestone, compare_milestones |
| Metamodel | upsert_node_type, delete_node_type, upsert_relation_type, delete_relation_type, upsert_viewpoint, delete_viewpoint |
| Radical Forge | forge_start · forge_clarify → forge_generate (with forge_propose_refinement → forge_answer_refinement when a stage finds what an earlier one lacks) → forge_complete_stage → forge_arrange, per stage · forge_wireframe · forge_import_hub_concept · forge_finish |
- Writes go through the same schemas and metamodel rules as Studio. An invalid parent, type or pair is refused with a message; warnings come back with the result. A tool reports success only after the files are written.
- A reference such as a transition's event takes an element's id, or a
tempIdfrom the same session. - Changing a built-in metamodel saves a -custom copy and re-announces the tools with the new types.
- The server keeps a Forge run in
.radical/forge-run.json, and refuses direct writes to earlier stages while a proposal waits. In Claude Code,/mcp__radical-folder__forgestarts a run.
Editing beside an agent
Studio and an agent can work on one folder at the same time; neither overwrites the other.
- Turns. After each write the server marks the folder as being written (
.radical/agent-activity.json) for 15 seconds. Studio holds its saves meanwhile, keeps your edits on top of the agent's, and saves them when the agent pauses. A reload keeps them in the browser until the folder has them. - Merges. Changes are merged element by element and field by field. Where both sides changed one value, what is in the folder is kept and a notice names it. What one side deleted stays deleted, with what the other side built on it, and the notice names that too. Two agents on one folder take turns through
.radical/write.lock. - What stays. An agent's change leaves your view, selection, camera and milestone as they were. While you drag, the change waits for the drop; while a presentation plays, until it stops.
- Undo. Your Undo and Redo take back your own steps only. Where a step meets a value or an element the agent changed since, the agent's version stays and a notice names it.
- Files. A file that does not read as a model (conflict markers, a trailing comma) is never merged over: Studio says which file and saves nothing until it reads again.
File formats
.radical (JSON)
One file: nodes, relations, sequences, views (positions, camera and layout constraints per view), defaultEdgeStyle, snapshots (milestones), presentations, the metamodel and Hub template records. Older .c4.json files open unchanged.
Markdown folder
my-model/
├─ radical.md # manifest
├─ nodes/
│ ├─ retail-customer.md # one element = one file
│ └─ core-banking-platform/ # an element with children becomes a directory
│ ├─ _index.md # the element itself
│ └─ payments-service/
│ ├─ _index.md
│ └─ fx-engine.md
├─ relations.json
├─ views.json · sequences.json · snapshots.json · presentations.json
├─ metamodel.json · hubTemplates.json
├─ _layout.json # positions, camera, line style — the only noisy file
├─ check.json # optional: rule settings for radical check and the Inspector
└─ .radical/ # editor state, kept out of git by its own .gitignore
├─ selection.json # what is selected in Studio, for the MCP server
├─ base.json # the model where the branch left main
├─ forge-run.json # where an agent's Forge run stands
├─ agent-activity.json # an agent is writing
└─ test-results.json # test cases from the last radical check --report
- Each
.mdhas YAML front-matter (id,type,label, then the properties, sorted) and the description as body. Hierarchy is the directory tree. - Output is deterministic: sorted keys, stable file names. A file is named after its element and keeps its name until the element is renamed or moved; two of one name are
orders-db.mdandorders-db-2.md. - Edit the files by hand or through the MCP server; Studio picks them up and merges what you have not saved yet. A file with a byte-order mark reads as any other.
Deep links
Studio keeps the place on screen in the URL hash, so any place can be bookmarked or shared.
#/m/<mode>/v/<viewId>[/t/<tab>][/f/<elementId>][/e/<elementId>][/s/<milestoneId>]
#/d/<docId>/m/<mode>/v/<viewId>[/p/<presentationId>/play/1/sl/<n>]
| Part | Meaning |
|---|---|
m | designer · viewer · presenter · metamodel · inspector |
v | A view id, or canvas for the default structure view |
t | The Inspector's tab: changes · model · implementation · settings |
f · e | The wiki page shown · the selected element |
s | The active milestone |
p · sl | The presentation and the 0-based slide while presenting |
d | Which model: ls:<id>, fs:<path> or md:<folder>, local to this machine |
File and folder paths open only in the desktop app; in the browser a folder is identified by its id, so its links work in the browser that opened it. The Hub uses #/browse for the catalogue and #/c/<conceptId>/v/canvas|wiki|table for one pack; studio.radical.tools/?hub=id1,id2 opens Studio with those packs queued for import.
Keyboard shortcuts
| Keys | Action |
|---|---|
| ⌘/Ctrl+P | Quick Search (and AI prompt) |
| Tab / ⌘/Ctrl+Enter | In Quick Search: switch to AI mode / send to AI |
| ⌘/Ctrl+Z · ⌘/Ctrl+⇧+Z | Undo · Redo (Designer) |
| The special key: Alt/⌥ (Settings → Special key) | Held with an element selected: mark where a relation from it, or nesting, can go |
| Special key + drag from an element | Connect it (or the selected elements) to another, or nest them there, on a pill; to the empty canvas: take them out of their container (those the metamodel keeps there are named). One step for Undo; in Viewer and Presenter it only selects |
| Special key + drag a relation's end | Move the end, keeping the relation's type |
| Special key + click | Add an element to the selection, or take it out |
| Special key + drag on the background | Select with a box |
| Special key + drop from the palette | Add the element without its wizard |
| ⌘/Ctrl + drag | Drag with the live physics making room |
| Double-click an element, relation or row | Open its properties card (a click only selects; an open card follows the selection) |
| F2 | Rename the selected row in place (a table, Warnier) |
| Delete | Delete the selection (Designer; fn+⌫ on a Mac) |
| Double-click the empty canvas | New Software System at the pointer |
| Esc | Cancel a connection, close dialogs, leave edit mode, stop the presentation; go up a level in a Hierarchy view |
| F5 | Start / stop the presentation |
| → ↓ Space · ← ↑ | Next · previous slide |
| Alt+← / Alt+→ | Back / forward (⌘+[ / ⌘+] on a Mac) |
| ⌘/Ctrl++ / − · ⌘/Ctrl+0 | Zoom in / out · fit (Flow views) |
| ⌘/Ctrl+Enter | In a wizard: create the element (Esc discards it) |
| Enter | Confirm inline edits (names, notes, table cells) |
The Warnier view's outline keys are in the guide.
Install & build
VS Code extension
The Radical.Tools extension opens .radical files in a Radical.Tools editor inside VS Code, keeps the file and the editor in sync both ways, and follows the editor's theme. Commands: Radical.Tools: Open current file, Open app, Stop and Show output log. Markdown folders open in Studio, not in VS Code.
Desktop app and a clone
# Node.js 20.11 or newer
git clone https://github.com/radicaltools/radical.tools.git
cd radical.tools
npm install
npm run dev # Electron, hot reload
npm run build && npm start # desktop app
npm run dist # packaged desktop app
npm run dev:web # browser build of Studio
npm run dev:hub # Concern Hub
npm run build -w @radicaltools/mcp # MCP server: node apps/mcp/dist/index.js --folder …
npm run build -w @radicaltools/cli # radical: node apps/cli/dist/index.js check …
npm test # unit tests of every workspace
npm run e2e # browser tests
npm run check:architecture # radical check on this repository's own model
The desktop app adds native file dialogs, Markdown folders without browser permissions and --file watching (or the RADICAL_FILE variable). Everything else is identical to the browser build. Studio, the desktop app, the VS Code extension, the MCP server and the command line share one version; a build that is not a release shows the commit after it.