diff --git a/docs/guides/javascript/react/theming.md b/docs/guides/javascript/react/theming.md
index f2ef85dab..6bc0c78a1 100644
--- a/docs/guides/javascript/react/theming.md
+++ b/docs/guides/javascript/react/theming.md
@@ -141,6 +141,61 @@ export const ExampleComponent = (props) => {
```
+## Generating overrides with the swizzle CLI
+
+
+
+The **swizzle CLI** generates the override files described above for you, instead of you creating them by hand. It scaffolds either a `wrap` (a component that decorates the original) or an `eject` (a full copy of the original source) into your theme.
+
+Run it from the project root, or from inside a `public/theme/` directory to have the target theme inferred automatically:
+
+```bash
+npm run swizzle
+```
+
+This launches an interactive wizard that asks you to pick a component, an action (`wrap` or `eject`), and a target theme, then generates the files for you. Once generated, run `grunt react[:watch]` to compile the override.
+
+### Risk profiles
+
+Not every component is safe to override. A component's public-facing props are usually stable, but its internal markup and children can change between releases. Each swizzleable component declares an independent safety level for **eject** and **wrap** in its plugin's `js/esm/src/swizzle.json`:
+
+| Level | Meaning |
+| --- | --- |
+| `safe` | Stable enough to override with minimal upgrade risk. |
+| `risky` | Works, but internals may change between minor releases, so you may need to revisit the override after upgrading. |
+| `prohibited` | Blocked by the component's author, usually because the component depends on internal implementation details that are not part of its public API. |
+
+The CLI enforces these levels: a `risky` action asks for confirmation before continuing, and a `prohibited` action is refused outright, with a suggestion to look for a hook, event, or a nearby `safe`/`risky` component instead.
+
+A plugin's `swizzle.json` maps each module name to its levels, for example:
+
+```json title="public/lib/js/esm/src/swizzle.json"
+{
+ "ExampleComponent": {
+ "eject": "risky",
+ "wrap": "safe"
+ }
+}
+```
+
+:::info[Undeclared components default to risky]
+
+Every `grunt react`/`grunt esm` build scans for swizzleable components with no entry in their plugin's `swizzle.json`, and adds one that defaults both `eject` and `wrap` to `risky`. This keeps the manifest up to date automatically as components are added. A plugin author only needs to loosen a component to `safe` or tighten one to `prohibited`, either by hand-editing `swizzle.json` or with the `manifest set` command described below.
+
+:::
+
+### Setting a component's safety level
+
+Plugin authors can set a component's levels directly, without hand-editing `swizzle.json`, with:
+
+```bash
+./scripts/swizzle.mjs manifest set [specifier] [ejectLevel] [wrapLevel]
+```
+
+- Omit `specifier` and the levels for an interactive prompt that lets you pick the component and level.
+- Provide a specifier and one level (for example, `./scripts/swizzle.mjs manifest set @moodle/lms/mod_assign/local/grader/GradingPanel safe`) to set both `eject` and `wrap` to that level.
+- Provide a specifier and two levels (eject, then wrap) to set them independently.
+
## Testing theme overrides
You can write tests for your theme-specific overrides in the same way that tests can be written for other components.