@lowdefy/docs-content 0.0.0-experimental-20260928120643 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/content/actions/link.md +0 -17
- package/content/actions/login.md +5 -23
- package/content/actions/logout.md +5 -5
- package/content/actions/pdfmake.md +2 -2
- package/content/actions/setdarkmode.md +2 -2
- package/content/agents/agent-properties.md +2 -4
- package/content/agents/agentchat.md +6 -21
- package/content/agents/agentconversations.md +2 -2
- package/content/concepts/ai-agent-docs.md +101 -313
- package/content/concepts/cli.md +3 -34
- package/content/concepts/connections-and-requests.md +0 -402
- package/content/concepts/custom-html.md +0 -40
- package/content/concepts/custom-styling.md +5 -50
- package/content/concepts/events-and-actions.md +2 -64
- package/content/concepts/i18n.md +2 -7
- package/content/concepts/keyboard-shortcuts.md +2 -2
- package/content/concepts/layout-overview.md +1 -1
- package/content/concepts/logger.md +0 -81
- package/content/concepts/lowdefy-schema.md +1 -4
- package/content/concepts/menus.md +7 -7
- package/content/concepts/module-authoring.md +2 -2
- package/content/connections/anthropic.md +2 -162
- package/content/connections/awss3.md +0 -54
- package/content/connections/google.md +2 -162
- package/content/connections/mongodb.md +3 -121
- package/content/connections/openai-connection.md +2 -162
- package/content/container-blocks/affix.md +7 -47
- package/content/container-blocks/alert.md +24 -76
- package/content/container-blocks/badge.md +24 -100
- package/content/container-blocks/box.md +9 -9
- package/content/container-blocks/card.md +25 -80
- package/content/container-blocks/carousel.md +7 -60
- package/content/container-blocks/collapse.md +9 -87
- package/content/container-blocks/configprovider.md +13 -35
- package/content/container-blocks/confirmmodal.md +23 -69
- package/content/container-blocks/content.md +98 -62
- package/content/container-blocks/descriptions.md +4 -45
- package/content/container-blocks/drawer.md +28 -92
- package/content/container-blocks/dropdownmenu.md +31 -119
- package/content/container-blocks/flex.md +62 -40
- package/content/container-blocks/footer.md +11 -15
- package/content/container-blocks/googlemapsheatmap.md +1 -1
- package/content/container-blocks/googlemapsscript.md +2 -2
- package/content/container-blocks/header.md +36 -71
- package/content/container-blocks/label.md +7 -34
- package/content/container-blocks/layout.md +34 -52
- package/content/container-blocks/masonry.md +71 -17
- package/content/container-blocks/mobilemenu.md +88 -131
- package/content/container-blocks/modal.md +26 -114
- package/content/container-blocks/pageheadermenu.md +31 -81
- package/content/container-blocks/pagesidebarlayout.md +26 -169
- package/content/container-blocks/pagesidermenu.md +42 -95
- package/content/container-blocks/popover.md +31 -34
- package/content/container-blocks/result.md +21 -32
- package/content/container-blocks/sider.md +122 -85
- package/content/container-blocks/span.md +7 -7
- package/content/container-blocks/spinner.md +3 -3
- package/content/container-blocks/splitter.md +68 -150
- package/content/container-blocks/tabs.md +12 -64
- package/content/container-blocks/tooltip.md +46 -22
- package/content/container-blocks/watermark.md +4 -22
- package/content/controls/reject.md +2 -4
- package/content/controls/throw.md +0 -1
- package/content/controls/try.md +2 -3
- package/content/deployment/deployment-environments.md +6 -8
- package/content/deployment/docker.md +7 -22
- package/content/deployment/node-server.md +0 -4
- package/content/deployment/vercel.md +6 -13
- package/content/display-blocks/aggrid.md +11 -26
- package/content/display-blocks/anchor.md +15 -15
- package/content/display-blocks/avatar.md +37 -57
- package/content/display-blocks/breadcrumb.md +21 -70
- package/content/display-blocks/button.md +18 -92
- package/content/display-blocks/calendar.md +0 -12
- package/content/display-blocks/dangeroushtml.md +1 -1
- package/content/display-blocks/difflist.md +1 -1
- package/content/display-blocks/difftimeline.md +1 -1
- package/content/display-blocks/divider.md +3 -64
- package/content/display-blocks/dropdownbutton.md +28 -79
- package/content/display-blocks/echart.md +1 -35
- package/content/display-blocks/floatbutton.md +42 -129
- package/content/display-blocks/html.md +1 -61
- package/content/display-blocks/icon.md +67 -250
- package/content/display-blocks/menu.md +73 -145
- package/content/display-blocks/message.md +124 -38
- package/content/display-blocks/notification.md +222 -94
- package/content/display-blocks/paragraph.md +9 -59
- package/content/display-blocks/progress.md +17 -96
- package/content/display-blocks/qrcode.md +4 -19
- package/content/display-blocks/s3download.md +1 -1
- package/content/display-blocks/search.md +7 -17
- package/content/display-blocks/skeletonbutton.md +0 -1
- package/content/display-blocks/skeletoninput.md +0 -1
- package/content/display-blocks/statistic.md +17 -75
- package/content/display-blocks/steps.md +25 -58
- package/content/display-blocks/tag.md +17 -102
- package/content/display-blocks/title.md +11 -50
- package/content/display-blocks/tour.md +23 -33
- package/content/input-blocks/autocomplete.md +9 -81
- package/content/input-blocks/buttonselector.md +8 -45
- package/content/input-blocks/checkboxselector.md +7 -97
- package/content/input-blocks/checkboxswitch.md +3 -33
- package/content/input-blocks/colorselector.md +14 -63
- package/content/input-blocks/daterangeselector.md +45 -165
- package/content/input-blocks/dateselector.md +41 -139
- package/content/input-blocks/datetimeselector.md +49 -158
- package/content/input-blocks/inputgallery.md +3 -3
- package/content/input-blocks/monthselector.md +52 -120
- package/content/input-blocks/multipleselector.md +39 -150
- package/content/input-blocks/numberinput.md +12 -98
- package/content/input-blocks/pagination.md +14 -70
- package/content/input-blocks/paragraphinput.md +37 -51
- package/content/input-blocks/passwordinput.md +6 -60
- package/content/input-blocks/phonenumberinput.md +26 -59
- package/content/input-blocks/radioselector.md +7 -83
- package/content/input-blocks/ratingslider.md +26 -57
- package/content/input-blocks/s3uploadbutton.md +24 -24
- package/content/input-blocks/s3uploaddragger.md +3 -3
- package/content/input-blocks/s3uploadphoto.md +5 -5
- package/content/input-blocks/segmentedselector.md +32 -72
- package/content/input-blocks/selector.md +21 -109
- package/content/input-blocks/switch.md +17 -65
- package/content/input-blocks/textarea.md +3 -32
- package/content/input-blocks/textinput.md +28 -69
- package/content/input-blocks/tiptapmentioninput.md +1 -1
- package/content/input-blocks/titleinput.md +12 -39
- package/content/input-blocks/treeinput.md +25 -49
- package/content/input-blocks/treemultipleselector.md +10 -127
- package/content/input-blocks/treeselector.md +9 -97
- package/content/input-blocks/upload.md +15 -64
- package/content/input-blocks/uploaddragger.md +1 -17
- package/content/input-blocks/uploadphoto.md +1 -18
- package/content/input-blocks/weekselector.md +55 -120
- package/content/list-blocks/controlledlist.md +15 -24
- package/content/list-blocks/list.md +11 -11
- package/content/list-blocks/masonrylist.md +34 -7
- package/content/migration/upgrade-guide.md +0 -1
- package/content/operators/_app.md +1 -2
- package/content/operators/_error.md +1 -23
- package/content/operators/_get.md +6 -6
- package/content/operators/_operator.md +3 -17
- package/content/operators/_ref.md +0 -258
- package/content/operators/_type.md +3 -14
- package/content/operators/_user.md +3 -3
- package/content/other/introduction.md +1 -1
- package/content/plugins/plugins-dev.md +0 -66
- package/content/plugins/plugins-introduction.md +1 -27
- package/content/testing/e2e-configuration.md +1 -8
- package/content/testing/e2e-getting-started.md +1 -1
- package/content/testing/e2e-introduction.md +1 -1
- package/content/tutorial/tutorial-actions-operators.md +2 -2
- package/content/tutorial/tutorial-add-blocks.md +2 -2
- package/content/tutorial/tutorial-create-page.md +2 -48
- package/content/tutorial/tutorial-display-data-page.md +3 -3
- package/content/tutorial/tutorial-requests-sql.md +0 -153
- package/content/tutorial/tutorial-start.md +1 -66
- package/content/user-authentication/login-and-logout.md +8 -158
- package/content/user-authentication/users-introduction.md +0 -8
- package/index.json +2 -6065
- package/package.json +1 -7
- package/scripts/extractAgentDocs.js +4 -36
- package/content/actions/emailotpsend.md +0 -58
- package/content/actions/emailotpverify.md +0 -77
- package/content/actions/getlocalstorage.md +0 -41
- package/content/actions/magiclinkverify.md +0 -113
- package/content/actions/posthogalias.md +0 -29
- package/content/actions/posthogcapture.md +0 -49
- package/content/actions/posthogcapturepageleave.md +0 -38
- package/content/actions/posthogfeatureflag.md +0 -50
- package/content/actions/posthoggroup.md +0 -37
- package/content/actions/posthogidentify.md +0 -54
- package/content/actions/posthoginit.md +0 -66
- package/content/actions/posthogoptin.md +0 -29
- package/content/actions/posthogoptout.md +0 -29
- package/content/actions/posthogpageview.md +0 -37
- package/content/actions/posthogreloadfeatureflags.md +0 -47
- package/content/actions/posthogreset.md +0 -28
- package/content/actions/posthogsetpersonproperties.md +0 -36
- package/content/actions/removelocalstorage.md +0 -26
- package/content/actions/setlocalstorage.md +0 -32
- package/content/adapter-reference/mongodbauthadapter.md +0 -46
- package/content/agents/agents-introduction.md +0 -107
- package/content/callback-reference/auth0logoutcallback.md +0 -54
- package/content/concepts/blocks.md +0 -150
- package/content/concepts/dynamic-page-content.md +0 -304
- package/content/concepts/html-attributes.md +0 -285
- package/content/concepts/lowdefy-api.md +0 -1110
- package/content/concepts/notifications.md +0 -155
- package/content/concepts/page-and-app-state.md +0 -244
- package/content/concepts/theming.md +0 -582
- package/content/connections/aigateway.md +0 -368
- package/content/connections/axioshttp.md +0 -181
- package/content/controls/while.md +0 -46
- package/content/display-blocks/clickablehtml.md +0 -239
- package/content/display-blocks/eventlog.md +0 -363
- package/content/display-blocks/pollingtimer.md +0 -263
- package/content/input-blocks/captcha.md +0 -40
- package/content/input-blocks/placesautocomplete.md +0 -319
- package/content/input-blocks/tagmultipleselector.md +0 -114
- package/content/input-blocks/tagselector.md +0 -114
- package/content/migration/auth-upgrade.md +0 -327
- package/content/migration/v3-to-v4.md +0 -417
- package/content/migration/v6-to-v7.md +0 -222
- package/content/operators/_cron.md +0 -292
- package/content/other/mongodbadapter.md +0 -3
- package/content/plugins/plugins-icon-sets.md +0 -267
- package/content/plugins/posthog.md +0 -275
- package/content/provider-reference/auth-js-providers.md +0 -107
- package/content/provider-reference/openidconnectprovider.md +0 -44
- package/content/testing/config-tests.md +0 -278
- package/content/tutorial/tutorial-requests-api.md +0 -155
- package/content/user-authentication/auth-configuration.md +0 -266
- package/content/user-authentication/auth-steps.md +0 -138
- package/content/user-authentication/mcp-oauth.md +0 -292
- package/content/user-authentication/organizations.md +0 -221
- package/content/user-authentication/protected-pages-apis.md +0 -97
- package/content/user-authentication/roles.md +0 -49
- package/content/user-authentication/two-factor.md +0 -229
- package/content/user-authentication/user-object.md +0 -58
- package/content/websockets/websocket-publish.md +0 -108
- package/content/websockets/websocket-subscriptions.md +0 -100
- package/content/websockets/websockets-introduction.md +0 -97
- package/hazards.json +0 -44
- package/scripts/hashDocSources.js +0 -38
- package/scripts/recordSourceHashes.js +0 -88
|
@@ -2,92 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
When you run `lowdefy dev`, the development server also serves a documentation API and an [MCP](https://modelcontextprotocol.io) endpoint built for AI coding agents. It describes everything installed in _your_ project — every block, operator, action, connection and request type from core Lowdefy plugins _and_ your own local plugins — plus the full Lowdefy documentation as markdown. This means an agent like Claude Code never has to guess type names or property shapes: it can look up the exact schema, real examples, and the relevant docs page while it writes your config.
|
|
4
4
|
|
|
5
|
-
Everything is served under the `/lowdefy-docs` path of your dev server.
|
|
5
|
+
Everything is served under the `/lowdefy-docs` path of your dev server (default `http://localhost:3000`). No setup or configuration is needed — it is always on in dev, and never part of your production server.
|
|
6
6
|
|
|
7
7
|
> The `/lowdefy-docs` route prefix is reserved by the dev server. A page with `id: lowdefy-docs` will not be reachable in dev.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## The MCP endpoint
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The dev server exposes an MCP server (streamable HTTP) at:
|
|
12
12
|
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
"mcpServers": {
|
|
16
|
-
"lowdefy-docs": {
|
|
17
|
-
"type": "stdio",
|
|
18
|
-
"command": "node",
|
|
19
|
-
"args": ["apps/main/node_modules/lowdefy/dist/index.js", "mcp"]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
13
|
+
```
|
|
14
|
+
http://localhost:3000/lowdefy-docs/mcp
|
|
23
15
|
```
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
| Tool | Purpose |
|
|
54
|
-
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
-
| `lowdefy_overview` | Start here — what is installed, counts per kind, and how to use the rest |
|
|
56
|
-
| `lowdefy_list_types` | List ALL available types of a kind (blocks, operators, actions, connections, requests) |
|
|
57
|
-
| `lowdefy_list_plugins` | Installed plugin packages, including local plugins, and the types each provides |
|
|
58
|
-
| `lowdefy_get_schema` | JSON Schema for a specific type — all properties and events |
|
|
59
|
-
| `lowdefy_get_examples` | Real YAML usage examples for a block type |
|
|
60
|
-
| `lowdefy_get_doc` | A Lowdefy docs page as markdown, by slug or by type name |
|
|
61
|
-
| `lowdefy_search_docs` | Keyword search over the Lowdefy docs |
|
|
62
|
-
| `lowdefy_search_icons` | Search icon names: semantic names first, then Lucide names, then the names of installed icon sets (qualified). Never invent an icon name |
|
|
63
|
-
| `lowdefy_get_plugin_doc` | Markdown (READMEs, guides) shipped inside an installed plugin package |
|
|
64
|
-
| `lowdefy_build_status` | Current build errors and warnings (with source file locations) plus recent browser runtime errors — call after every edit |
|
|
65
|
-
| `lowdefy_check` | Validate the whole app as `lowdefy build` would, without building — every page, and the prod-only checks dev shows as warnings come back as errors. Call before calling a change done |
|
|
66
|
-
| `lowdefy_get_page_config` | The fully built config for a page, or its structured build errors |
|
|
67
|
-
| `lowdefy_screenshot_page` | PNG screenshot of a rendered page (headless Chromium) for visual verification; `width`, `height` and `colorScheme: "dark"` check a phone layout or dark mode |
|
|
68
|
-
| `lowdefy_run_journey` | Drive a page headless through declarative steps (`click`, `fill`, `goto`, `email`, `as`, `expect`, …) and assert state, visibility, text, url, title or email — verify behaviour, not just layout |
|
|
69
|
-
| `lowdefy_find_config` | Which yaml file (and line) defines a given page, block, or request id |
|
|
70
|
-
| `lowdefy_scaffold_page` | Create a new page yaml file with a canonical minimal structure |
|
|
71
|
-
| `lowdefy_app_map` | The whole-app graph: every page, menu, connection, endpoint, and agent in one call |
|
|
72
|
-
| `lowdefy_inspect_state` | The LIVE state, request results, and event log of a running page — reads your open browser tab, or runs the page headless |
|
|
73
|
-
| `lowdefy_eval_operator` | Evaluate any operator expression against live page state — a REPL for config |
|
|
74
|
-
| `lowdefy_run_request` | Execute a request with a test payload, as a given `user`, to verify data shape (read-only unless opted in) |
|
|
75
|
-
| `lowdefy_run_endpoint` | Execute an Api endpoint routine with a test payload, as a given `user` or as a system context (`system: true`), to see what it returns, rejects or throws (needs `allowWriteRequests`; a `:reject` comes back as data) |
|
|
76
|
-
| `lowdefy_snapshot_state` | Capture live page state + request responses into a committable checkpoint folder |
|
|
77
|
-
| `lowdefy_load_state` | Restore a state checkpoint — headless, or a `?_checkpoint=` URL for manual testing |
|
|
78
|
-
| `lowdefy_list_state_checkpoints` | List saved state checkpoints |
|
|
79
|
-
| `lowdefy_checkpoint_to_mocks` | Convert a state checkpoint into e2e `mocks.yaml` fixtures |
|
|
80
|
-
| `lowdefy_restart` | Restart the dev server process — after editing a local plugin's server-side code, or when `build_status` looks stale. Then call `lowdefy_build_status` with `wait: true`, which answers once the server is back |
|
|
81
|
-
| `lowdefy_checkpoint` | Snapshot all config files before risky changes |
|
|
82
|
-
| `lowdefy_revert_checkpoint` | Restore config files from a checkpoint |
|
|
83
|
-
|
|
84
|
-
## Hazards — what the schema cannot tell you
|
|
85
|
-
|
|
86
|
-
A hazard is a behaviour of a type that its schema does not show, but that an agent must know before writing config: the `Html` block sanitises its content, so a `<style>` tag is stripped; closing a `Modal` keeps the state of the blocks inside it, while `visible: false` prunes it; `_state` inside a request's `properties` is always `undefined`; a `_ref` to a `.njk` file renders at build time. Each hazard is `{ id, message, see }` — a stable kebab-case `id`, one or two sentences saying what happens and what to do instead, and a docs slug (or `null`) for `lowdefy_get_doc`.
|
|
87
|
-
|
|
88
|
-
`lowdefy_get_schema`, `lowdefy_get_doc` (when looked up by kind and type) and `lowdefy_find_config` (per match) return `hazards` alongside their normal result — `lowdefy_get_doc` appends them as a `## Hazards` section of the markdown. Some hazards are contextual: `tenant-wall-lookup` is only returned for a request whose connection is tenant-walled, so `find_config` on that request explains the wall's `$lookup` injection while the same request over a `tenant: shared` connection stays quiet.
|
|
89
|
-
|
|
90
|
-
Hazards come from two places. Framework-level hazards ship with `@lowdefy/docs-content` (`hazards.json`). Type-attached hazards are declared by the plugin: a block sets `meta.hazards`, a request sets `meta.hazards` on the request function, and an operator package exports a `./metas` module with `{ hazards }` per operator — see [Plugins](/plugins-introduction). Local plugins in your project use the same channel, so your own blocks can warn an agent about their own surprises.
|
|
17
|
+
It provides these tools:
|
|
18
|
+
|
|
19
|
+
| Tool | Purpose |
|
|
20
|
+
| ------------------------ | ----------------------------------------------------------------------- |
|
|
21
|
+
| `lowdefy_overview` | Start here — what is installed, counts per kind, and how to use the rest |
|
|
22
|
+
| `lowdefy_list_types` | List ALL available types of a kind (blocks, operators, actions, connections, requests) |
|
|
23
|
+
| `lowdefy_list_plugins` | Installed plugin packages, including local plugins, and the types each provides |
|
|
24
|
+
| `lowdefy_get_schema` | JSON Schema for a specific type — all properties and events |
|
|
25
|
+
| `lowdefy_get_examples` | Real YAML usage examples for a block type |
|
|
26
|
+
| `lowdefy_get_doc` | A Lowdefy docs page as markdown, by slug or by type name |
|
|
27
|
+
| `lowdefy_search_docs` | Keyword search over the Lowdefy docs |
|
|
28
|
+
| `lowdefy_get_plugin_doc` | Markdown (READMEs, guides) shipped inside an installed plugin package |
|
|
29
|
+
| `lowdefy_build_status` | Current build errors and warnings (with source file locations) plus recent browser runtime errors — call after every edit |
|
|
30
|
+
| `lowdefy_get_page_config`| The fully built config for a page, or its structured build errors |
|
|
31
|
+
| `lowdefy_screenshot_page`| PNG screenshot of a rendered page (headless Chromium) for visual verification |
|
|
32
|
+
| `lowdefy_find_config` | Which yaml file (and line) defines a given page, block, or request id |
|
|
33
|
+
| `lowdefy_scaffold_page` | Create a new page yaml file with a canonical minimal structure |
|
|
34
|
+
| `lowdefy_app_map` | The whole-app graph: every page, menu, connection, endpoint, and agent in one call |
|
|
35
|
+
| `lowdefy_inspect_state` | The LIVE state, request results, and event log of a running page — reads your open browser tab, or runs the page headless |
|
|
36
|
+
| `lowdefy_eval_operator` | Evaluate any operator expression against live page state — a REPL for config |
|
|
37
|
+
| `lowdefy_run_request` | Execute a request with a test payload to verify data shape (read-only unless opted in) |
|
|
38
|
+
| `lowdefy_snapshot_state` | Capture live page state + request responses into a committable checkpoint folder |
|
|
39
|
+
| `lowdefy_load_state` | Restore a state checkpoint — headless, or a `?_checkpoint=` URL for manual testing |
|
|
40
|
+
| `lowdefy_list_state_checkpoints` | List saved state checkpoints |
|
|
41
|
+
| `lowdefy_checkpoint_to_mocks` | Convert a state checkpoint into e2e `mocks.yaml` fixtures |
|
|
42
|
+
| `lowdefy_checkpoint` | Snapshot all config files before risky changes |
|
|
43
|
+
| `lowdefy_revert_checkpoint` | Restore config files from a checkpoint |
|
|
91
44
|
|
|
92
45
|
## Annotate your app — point, draw, copy, paste
|
|
93
46
|
|
|
@@ -115,57 +68,19 @@ Hold **Option** (macOS) or **Alt** (Windows/Linux) and click any element in your
|
|
|
115
68
|
The dev server rebuilds automatically when config changes, so an agent works in a tight loop:
|
|
116
69
|
|
|
117
70
|
1. Discover types and schemas, write or edit YAML.
|
|
118
|
-
2. Call `lowdefy_build_status`
|
|
119
|
-
3.
|
|
120
|
-
4.
|
|
121
|
-
5. Runtime errors from the browser (operator errors, block render errors) also appear in `lowdefy_build_status` under `clientErrors`, so problems that only show at runtime still reach the agent.
|
|
122
|
-
6. Server-side failures appear beside them under `serverErrors` — a request whose database filter is malformed, an endpoint step that throws, an MCP tool call or an agent tool call that fails — each with the yaml `source` (`file:line`) and `config` path that produced it, plus the `endpointId`, `requestId` and `pageId` where known. The store holds the last 50 errors and is cleared on dev server restart.
|
|
123
|
-
7. Each browser and server error carries the `buildId` it happened under: the time of the latest config build or page edit. Errors from before the current build are listed apart under `earlierErrors`, since they may already be fixed; `clientErrors` and `serverErrors` hold only errors under the current build.
|
|
124
|
-
|
|
125
|
-
### Events are pushed — no need to poll
|
|
126
|
-
|
|
127
|
-
The dev server pushes what changed instead of waiting to be asked. Two channels carry the same events:
|
|
128
|
-
|
|
129
|
-
- **MCP clients** receive them as `notifications/message` from logger `lowdefy` on the standalone GET stream of `/lowdefy-docs/mcp` (the server declares the `logging` capability, so any MCP client surfaces them). Failed builds arrive at level `error`, everything else at `info`.
|
|
130
|
-
- **Everything else** uses `GET /lowdefy-docs/events`, a Server-Sent Events stream — `curl -N http://localhost:3000/lowdefy-docs/events` — with one frame per event, named by the event type.
|
|
131
|
-
|
|
132
|
-
Every event carries `type` and an ISO `timestamp`. The four types:
|
|
133
|
-
|
|
134
|
-
| Type | When | Carries |
|
|
135
|
-
| -------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
-
| `restart` | First event on every connection | `bootedAt` — the dev server process start time, so a reconnecting client can tell a restart from a dropped connection |
|
|
137
|
-
| `build` | Every time a rebuild finishes, success or failure | `status`, `errorCount`, `warningCount`, `errors`, `warnings`, and `stale` / `staleSince` (see below) |
|
|
138
|
-
| `client_error` | A browser reports a runtime error | The same entry `lowdefy_build_status` lists under `clientErrors` |
|
|
139
|
-
| `server_error` | A request, endpoint, MCP tool or agent tool fails on the server | The same entry `lowdefy_build_status` lists under `serverErrors` |
|
|
140
|
-
|
|
141
|
-
Events are not buffered: a client that connects after an event missed it, and should call `lowdefy_build_status` — which is derived from the same `build/buildStatus.json` — for the current picture. Act on a `build` event with `status: "error"` immediately; `lowdefy_build_status` remains the full report.
|
|
142
|
-
|
|
143
|
-
### When a build fails, answers are marked stale
|
|
144
|
-
|
|
145
|
-
A failed rebuild does not take the dev server down — it keeps serving the last build that succeeded, so you can carry on looking at the app while you fix the error. That means every tool can keep answering from a build that predates the latest edits, which is a trap for an agent.
|
|
146
|
-
|
|
147
|
-
So while the last build is failing, every answer says so:
|
|
148
|
-
|
|
149
|
-
- MCP tool results start with a `STALE: ...` text item.
|
|
150
|
-
- JSON responses from `/lowdefy-docs` carry `stale: true`, `staleSince` and `staleReason`.
|
|
151
|
-
- Markdown responses are prefixed with a `> STALE: ...` banner.
|
|
152
|
-
- Every `/lowdefy-docs` response carries the `X-Lowdefy-Stale` and `X-Lowdefy-Stale-Since` headers.
|
|
153
|
-
|
|
154
|
-
Nothing is refused — the last-known-good schema or page config is often exactly what you need while fixing the build. The flag disappears as soon as a build succeeds. Call `lowdefy_build_status` (or `GET /lowdefy-docs/build-status`) for the errors.
|
|
155
|
-
|
|
156
|
-
Some build warnings are only warnings in `lowdefy dev` — they fail `lowdefy build`. Those carry `"prodError": true` in `lowdefy_build_status`, are printed in the dev terminal as `[ConfigWarning · fails in prod] …`, and are badged **fails in prod** on a dark-orange bar in the browser error bar. Treat them as errors: the production build will not pass until they are fixed.
|
|
71
|
+
2. Call `lowdefy_build_status` — did the build succeed? Errors come back with the exact source file and location.
|
|
72
|
+
3. Call `lowdefy_get_page_config` to confirm the page builds, and `lowdefy_screenshot_page` to see it rendered.
|
|
73
|
+
4. Runtime errors from the browser (operator errors, block render errors) also appear in `lowdefy_build_status`, so problems that only show at runtime still reach the agent.
|
|
157
74
|
|
|
158
75
|
## Live state — the agent sees what you see
|
|
159
76
|
|
|
160
77
|
When you have a page open in your browser, the agent can read its **actual live state** — page state, request results, and the event log of recent actions — via `lowdefy_inspect_state`. Reproduce a problem by clicking through the app, then ask the agent to look: it inspects your exact tab, not a guess. `lowdefy_eval_operator` then evaluates any operator expression (like `{"_state": "customer.name"}`) against that same live context, so `_state`/`_request` binding bugs get debugged against real data. With no tab open, both tools run the page headless instead.
|
|
161
78
|
|
|
162
|
-
A headless capture waits for the page's full async lifecycle before it reads anything: `onInit`, `onInitAsync`, `onMount` and `onMountAsync`, every in-flight request, and the first message on each websocket subscription. A page whose data arrives through an `onMountAsync` `Request` action is therefore captured with its data, not empty. If a page has not settled within 15 seconds the result is still returned, carrying `ready: false` and a note — read that result as a snapshot of a page that was still loading, not as the page's settled state. One case escapes the wait: an event with a `debounce` is not yet marked loading during its delay, so a debounced `onMountAsync` can be captured before it runs.
|
|
163
|
-
|
|
164
79
|
## Auth-protected pages
|
|
165
80
|
|
|
166
|
-
The headless renderer behind `lowdefy_screenshot_page` and `lowdefy_inspect_state` authenticates as a signed-in user, so pages with `auth.public: false` render for the agent instead of
|
|
81
|
+
The headless renderer behind `lowdefy_screenshot_page` and `lowdefy_inspect_state` authenticates as a signed-in user, so pages with `auth.public: false` render for the agent instead of returning a 404. That default user carries **no roles**, so a page or request gated on a role still comes back refused or empty.
|
|
167
82
|
|
|
168
|
-
To act as a specific caller, pass `user` — every tool that renders a page headless accepts it
|
|
83
|
+
To act as a specific caller, pass `user` — every tool that renders a page headless accepts it: `lowdefy_screenshot_page`, `lowdefy_inspect_state`, `lowdefy_eval_operator` and `lowdefy_load_state`:
|
|
169
84
|
|
|
170
85
|
```json
|
|
171
86
|
{ "pageId": "users", "user": { "roles": ["admin"] } }
|
|
@@ -173,9 +88,9 @@ To act as a specific caller, pass `user` — every tool that renders a page head
|
|
|
173
88
|
|
|
174
89
|
It is merged over the default user, so `{"roles": [...]}` is usually all you need. No auth engine runs for an injected caller, so nothing derives the rest of the record — include `email`, `profile` or `attributes` in the object if the page reads them. Every call opens its own browser context, so one call can act as an admin and the next as a plain member.
|
|
175
90
|
|
|
176
|
-
`user` applies to the headless renderer only — it is never applied to a page you open in your own browser, which carries your real session and cannot be re-identified. `lowdefy_inspect_state` and `lowdefy_eval_operator` normally prefer your open tab, so passing `user` selects the headless source instead; combining it with `source: "tab"` is an error rather than a silently ignored role, as is combining it with `lowdefy_load_state`'s `mode: "registry-only"` (that mode hands you a URL to open yourself). The plain HTTP routes take the same param: `?user={"roles":["admin"]}` on the GET routes, a `user` key in the body of `POST /lowdefy-docs/
|
|
91
|
+
`user` applies to the headless renderer only — it is never applied to a page you open in your own browser, which carries your real session and cannot be re-identified. `lowdefy_inspect_state` and `lowdefy_eval_operator` normally prefer your open tab, so passing `user` selects the headless source instead; combining it with `source: "tab"` is an error rather than a silently ignored role, as is combining it with `lowdefy_load_state`'s `mode: "registry-only"` (that mode hands you a URL to open yourself). The plain HTTP routes take the same param: `?user={"roles":["admin"]}` on the GET routes, a `user` key in the body of `POST /lowdefy-docs/eval-operator` and `POST /lowdefy-docs/state-checkpoints/load`. They answer a malformed or contradictory `user` with a `400`, distinct from the `502` a failed render returns.
|
|
177
92
|
|
|
178
|
-
To bypass login for the whole dev server — your own browser included — start it with a mock user instead: `lowdefy dev --mock-user '{"
|
|
93
|
+
To bypass login for the whole dev server — your own browser included — start it with a mock user instead: `lowdefy dev --mock-user '{"sub":"dev","roles":["admin"]}'` (or configure `auth.dev.mockUser`). See [Auth Configuration](/auth-configuration#mock-user-for-testing-dev-server-only).
|
|
179
94
|
|
|
180
95
|
## State checkpoints — put the app in a known state
|
|
181
96
|
|
|
@@ -198,11 +113,7 @@ Loading it back (`lowdefy_load_state`) serves the recorded request data from the
|
|
|
198
113
|
|
|
199
114
|
## Running requests safely
|
|
200
115
|
|
|
201
|
-
`lowdefy_run_request` executes a request with a test payload so the agent can verify the data shape a page will receive. Read-only request types (like `MongoDBFind`) always run.
|
|
202
|
-
|
|
203
|
-
A response over 40,000 serialized characters is not returned inline: it is written in full to a JSON file under `.lowdefy/responses/` in the app directory, and the result carries `responseFile` (its path), `responseChars` and, for an array, `responseItems`. Pass `saveResponse: true` to always write the response there. `lowdefy_run_endpoint` does the same. Only the 20 most recent response files are kept.
|
|
204
|
-
|
|
205
|
-
Pass `user` to run the request as a specific caller — `{ "pageId": "users", "requestId": "get_users", "user": { "roles": ["admin"] } }`. Without `user` the request runs as a roleless anonymous caller, so a tenant-walled or role-gated request returns empty rows rather than an error. Impersonation never unlocks writes: the write gate below applies to every caller. Write requests are refused unless you opt in:
|
|
116
|
+
`lowdefy_run_request` executes a request with a test payload so the agent can verify the data shape a page will receive. Read-only request types (like `MongoDBFind`) always run. Write requests are refused unless you opt in:
|
|
206
117
|
|
|
207
118
|
```yaml
|
|
208
119
|
cli:
|
|
@@ -210,219 +121,97 @@ cli:
|
|
|
210
121
|
allowWriteRequests: true
|
|
211
122
|
```
|
|
212
123
|
|
|
213
|
-
|
|
124
|
+
This is dev-only — enable it when you're comfortable with the agent writing to your dev data.
|
|
214
125
|
|
|
215
|
-
|
|
126
|
+
## Setting up a project — one command
|
|
216
127
|
|
|
217
|
-
```
|
|
218
|
-
|
|
128
|
+
```bash
|
|
129
|
+
npx lowdefy agent-setup
|
|
219
130
|
```
|
|
220
131
|
|
|
221
|
-
|
|
132
|
+
This writes three files into your project (merging safely if they exist): `.mcp.json` registering the `lowdefy-docs` MCP server, `.claude/skills/lowdefy-config/SKILL.md` teaching Claude Code the workflow, and an `AGENTS.md` section for other coding agents. Use `--port` if your dev server doesn't run on 3000.
|
|
222
133
|
|
|
223
|
-
|
|
134
|
+
## Using it with Claude Code manually
|
|
224
135
|
|
|
225
|
-
|
|
136
|
+
Add the MCP server to your project so Claude Code can use it. In your project directory run:
|
|
226
137
|
|
|
227
|
-
```
|
|
228
|
-
|
|
138
|
+
```bash
|
|
139
|
+
claude mcp add --transport http lowdefy-docs http://localhost:3000/lowdefy-docs/mcp
|
|
229
140
|
```
|
|
230
141
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
This is dev-only — enable it when you're comfortable with the agent writing to your dev data.
|
|
234
|
-
|
|
235
|
-
## Journeys — verify behaviour, not just layout
|
|
236
|
-
|
|
237
|
-
A screenshot shows what rendered; it cannot tell the agent whether the form submits, the modal opens or the filter works. `lowdefy_run_journey` (or `POST /lowdefy-docs/journey`) opens a page headless and drives it through a declarative list of steps — a tiny Playwright — then reports what happened as data. Blocks are addressed by their `blockId`, through the same `#bl-<blockId>` DOM contract `@lowdefy/e2e-utils` uses, so a journey reads like the config it tests:
|
|
142
|
+
Or commit a `.mcp.json` file at your project root so the whole team gets it:
|
|
238
143
|
|
|
239
144
|
```json
|
|
240
145
|
{
|
|
241
|
-
"
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
{ "fill": { "blockId": "name", "value": "Ada Lovelace" } },
|
|
246
|
-
{ "select": { "blockId": "country", "value": "United Kingdom" } },
|
|
247
|
-
{ "click": "submit" },
|
|
248
|
-
{ "wait": { "request": "create_customer" } },
|
|
249
|
-
{ "expect": { "state": { "path": "created", "equals": true } } },
|
|
250
|
-
{ "expect": { "visible": "success_modal" } },
|
|
251
|
-
{ "expect": { "text": { "blockId": "success_message", "contains": "Ada Lovelace" } } },
|
|
252
|
-
{ "screenshot": "after-submit" },
|
|
253
|
-
{ "press": "Escape" },
|
|
254
|
-
{ "click": "go_to_list" },
|
|
255
|
-
{ "expect": { "url": { "contains": "/customers" } } }
|
|
256
|
-
]
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Every step is an object with exactly one key:
|
|
261
|
-
|
|
262
|
-
| Step | What it does |
|
|
263
|
-
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
264
|
-
| `{ "click": target }` | Clicks the block — its interactive control (button, link, input, checkbox…) when it has one, otherwise the block itself — or the control a target object narrows to (below) |
|
|
265
|
-
| `{ "fill": { ...target, value } }` | Fills the block's (or grid cell's) `input` or `textarea` with `value` (converted to a string) |
|
|
266
|
-
| `{ "select": { ...target, value } }` | Opens the block's (or grid cell's) dropdown and clicks the option whose text is exactly `value`; a native `<select>` inside the block is set by label instead, and a radio, button or segmented selector's option is clicked by its label |
|
|
267
|
-
| `{ "press": key }` | Presses a key or chord, e.g. `"Enter"`, `"Escape"`, `"Mod+k"` — `Mod` becomes `Meta` or `Control` for the platform the page reports, the same way the app's shortcuts resolve it |
|
|
268
|
-
| `{ "back": true }` | Goes back one page, like the browser's Back button; fails when the journey has not navigated from an earlier page |
|
|
269
|
-
| `{ "goto": pageId }` | Loads a page like a typed URL (`{ pageId, urlQuery }` adds a query); a protected page may redirect to sign-in, so assert where it landed |
|
|
270
|
-
| `{ "email": { to, subject? } }` | Opens the newest email to `to` that arrived during the journey, waiting for it; `click` follows its links by text. Needs `LOWDEFY_DEV_SMTP_PORT` |
|
|
271
|
-
| `{ "as": name }` | Switches to another person with their own browser and cookies; the journey starts as `"main"`, and a new name opens the journey's page |
|
|
272
|
-
| `{ "wait": { "ms": n } }` | Sleeps `n` milliseconds |
|
|
273
|
-
| `{ "wait": { "request": requestId } }` | Waits until the request has finished loading |
|
|
274
|
-
| `{ "wait": { "state": path } }` | Waits until the state path is defined |
|
|
275
|
-
| `{ "screenshot": name? }` | Captures a PNG of the viewport; returned with the result (`true`, `null` or a missing name defaults to `step-<index>`) |
|
|
276
|
-
| `{ "expect": { "state": { path, equals } } }` | The state at `path` structurally equals `equals` (key order does not matter); a path that does not exist reads as `null`, so `equals: null` also passes for a misspelt path |
|
|
277
|
-
| `{ "expect": { "visible": target } }` | The block, or the control a target narrows to, is visible |
|
|
278
|
-
| `{ "expect": { "text": { ...target, contains } } }` | The block's text — or a grid row's or cell's — contains the string |
|
|
279
|
-
| `{ "expect": { "url": { contains } } }` | The page url contains the string |
|
|
280
|
-
| `{ "expect": { "title": { equals } } }` | The document title (the browser tab's text) is exactly the string; `{ contains }` checks part of it |
|
|
281
|
-
|
|
282
|
-
A **target** is a `blockId` string, or an object that narrows the search to a control that is not itself a block — a grid row's cell buttons, a confirm dialog's OK, a dropdown menu's items:
|
|
283
|
-
|
|
284
|
-
| Target key | Meaning |
|
|
285
|
-
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
286
|
-
| `blockId` | The block to search inside |
|
|
287
|
-
| `row` | A grid row, zero-based as displayed (`AgGrid*` blocks, `.ag-row[row-index]`); needs `blockId` |
|
|
288
|
-
| `column` | A grid cell in that row, by the column's `field` or `colId` (`.ag-cell[col-id]`); needs `blockId` |
|
|
289
|
-
| `text` | The visible interactive control whose text is exactly this — a button label, a tab, a menu item (`"Cat"` never matches `"Category"`) |
|
|
290
|
-
| `nth` | When several controls match, the zero-based one to use |
|
|
291
|
-
|
|
292
|
-
A radio, checkbox or segmented option is reached through its label: `{ "click": { "blockId": "period", "text": "Month" } }` clicks the Month option of a `SegmentedSelector`, whose own radio input has no size.
|
|
293
|
-
|
|
294
|
-
`text` without a `blockId` searches the page, front-most layer first — an open dropdown menu (`[role="menu"]`), then an open dialog (`[role="dialog"]`), then the page — so `{ "click": { "text": "Delete" } }` with a confirm dialog open clicks the dialog's Delete and not the grid's, without counting buttons. `fill`, `select` and `expect.text` always need a `blockId`. Unknown target keys are rejected before a browser opens.
|
|
295
|
-
|
|
296
|
-
```json
|
|
297
|
-
[
|
|
298
|
-
{ "click": { "blockId": "controls_grid", "row": 1, "text": "Delete" } },
|
|
299
|
-
{ "expect": { "visible": { "text": "Are you sure?" } } },
|
|
300
|
-
{ "click": { "text": "Delete" } },
|
|
301
|
-
{ "wait": { "request": "delete_control" } },
|
|
302
|
-
{
|
|
303
|
-
"expect": {
|
|
304
|
-
"text": {
|
|
305
|
-
"blockId": "controls_grid",
|
|
306
|
-
"row": 1,
|
|
307
|
-
"column": "title",
|
|
308
|
-
"contains": "Key rotation"
|
|
309
|
-
}
|
|
146
|
+
"mcpServers": {
|
|
147
|
+
"lowdefy-docs": {
|
|
148
|
+
"type": "http",
|
|
149
|
+
"url": "http://localhost:3000/lowdefy-docs/mcp"
|
|
310
150
|
}
|
|
311
|
-
}
|
|
312
|
-
{ "click": { "blockId": "controls_grid", "row": 0, "column": "more" } },
|
|
313
|
-
{ "click": { "text": "Archive" } }
|
|
314
|
-
]
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
Each step gets 5 seconds (Playwright's own auto-waiting — a `click` waits for the block to be attached, visible and enabled; nothing is retried); pass `timeout` (milliseconds, up to 60000) to give every step of a journey longer on a slow machine. After an interaction the runner waits for the page to settle — the event the interaction fired, the requests it called — using the same readiness check the page open uses, so the next `expect` asserts against the outcome instead of racing it. The page opens with the same headless `user` and `urlQuery` handling as the other tools.
|
|
318
|
-
|
|
319
|
-
A step that fails **stops the journey and comes back as data**, never as a tool error — a failed journey is the answer, not a fault:
|
|
320
|
-
|
|
321
|
-
```json
|
|
322
|
-
{
|
|
323
|
-
"pageId": "new_customer",
|
|
324
|
-
"passed": false,
|
|
325
|
-
"steps": [
|
|
326
|
-
{
|
|
327
|
-
"index": 0,
|
|
328
|
-
"step": { "fill": { "blockId": "name", "value": "Ada Lovelace" } },
|
|
329
|
-
"status": "ok",
|
|
330
|
-
"durationMs": 18
|
|
331
|
-
},
|
|
332
|
-
{ "index": 1, "step": { "click": "submit" }, "status": "ok", "durationMs": 71 },
|
|
333
|
-
{
|
|
334
|
-
"index": 2,
|
|
335
|
-
"step": { "expect": { "state": { "path": "created", "equals": true } } },
|
|
336
|
-
"status": "failed",
|
|
337
|
-
"durationMs": 1
|
|
338
|
-
},
|
|
339
|
-
{ "index": 3, "step": { "screenshot": "after-submit" }, "status": "skipped", "durationMs": 0 }
|
|
340
|
-
],
|
|
341
|
-
"failure": {
|
|
342
|
-
"index": 2,
|
|
343
|
-
"step": { "expect": { "state": { "path": "created", "equals": true } } },
|
|
344
|
-
"expected": true,
|
|
345
|
-
"actual": null,
|
|
346
|
-
"message": "Expected state \"created\" to equal true but found undefined."
|
|
347
|
-
},
|
|
348
|
-
"screenshots": [],
|
|
349
|
-
"state": { "name": "Ada Lovelace", "country": null }
|
|
151
|
+
}
|
|
350
152
|
}
|
|
351
153
|
```
|
|
352
154
|
|
|
353
|
-
|
|
155
|
+
If your dev server runs on a different port, adjust the URL. The MCP server includes instructions that teach the agent the workflow (list types first, then fetch schemas and examples), so it works well without any extra prompting.
|
|
354
156
|
|
|
355
|
-
|
|
356
|
-
| ----------------------- | --------------------------------------------------------------------- |
|
|
357
|
-
| omitted | The whole state when it is small, otherwise `stateOmitted` |
|
|
358
|
-
| `["form.name", "rows"]` | `state: { "form.name": …, "rows": … }`, `null` for a path not defined |
|
|
359
|
-
| `true` | The whole state, however large |
|
|
360
|
-
| `false` | No state |
|
|
157
|
+
## Referencing it in a skill
|
|
361
158
|
|
|
362
|
-
|
|
159
|
+
For the best results, add a skill to your project that tells the agent to use the docs server whenever it writes Lowdefy config. Create `.claude/skills/lowdefy-config/SKILL.md`:
|
|
363
160
|
|
|
364
|
-
|
|
161
|
+
```markdown
|
|
162
|
+
---
|
|
163
|
+
name: lowdefy-config
|
|
164
|
+
description: Use when writing or editing Lowdefy YAML config — pages, blocks, operators, actions, connections, or requests. Looks up exact type names, schemas, and examples from the running dev server instead of guessing.
|
|
165
|
+
---
|
|
365
166
|
|
|
366
|
-
|
|
167
|
+
# Writing Lowdefy config
|
|
367
168
|
|
|
368
|
-
|
|
169
|
+
The dev server serves docs for everything installed in this project at
|
|
170
|
+
`http://localhost:3000/lowdefy-docs` (also as MCP tools via the `lowdefy-docs` server).
|
|
369
171
|
|
|
370
|
-
|
|
172
|
+
Never guess type names or properties. Before writing config:
|
|
371
173
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
Commit a `.mcp.json` file at your project root, pointing at your app's installed CLI:
|
|
174
|
+
1. Call `lowdefy_list_types` (or `GET /lowdefy-docs/blocks`, `/lowdefy-docs/operators`,
|
|
175
|
+
`/lowdefy-docs/actions`, `/lowdefy-docs/connections`, `/lowdefy-docs/requests`) to find the exact
|
|
176
|
+
type name — this includes this project's local plugins.
|
|
177
|
+
2. Call `lowdefy_get_schema` (or `GET /lowdefy-docs/schema/{kind}/{type}`) for the
|
|
178
|
+
exact properties and events of that type.
|
|
179
|
+
3. Call `lowdefy_get_examples` (or `GET /lowdefy-docs/examples/{type}`) to see real
|
|
180
|
+
usage YAML for blocks.
|
|
181
|
+
4. For concepts (state, operators, events, requests), call `lowdefy_get_doc`
|
|
182
|
+
or `lowdefy_search_docs`.
|
|
383
183
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"command": "node",
|
|
390
|
-
"args": ["node_modules/lowdefy/dist/index.js", "mcp"]
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
184
|
+
After every edit, call `lowdefy_build_status` and fix what it reports. Use
|
|
185
|
+
`lowdefy_inspect_state` to read the live state of the page (ask the developer
|
|
186
|
+
to interact with it first when debugging), `lowdefy_eval_operator` to test
|
|
187
|
+
operator expressions against real state, and `lowdefy_snapshot_state` /
|
|
188
|
+
`lowdefy_load_state` to capture and restore app states for testing.
|
|
394
189
|
```
|
|
395
190
|
|
|
396
|
-
In a monorepo, use the path to the app's `node_modules`, for example `apps/main/node_modules/lowdefy/dist/index.js`. The MCP server includes instructions that teach the agent the workflow (list types first, then fetch schemas and examples; let `lowdefy mcp` run the dev server), so it works well without any extra prompting.
|
|
397
|
-
|
|
398
191
|
## Plain HTTP routes
|
|
399
192
|
|
|
400
193
|
Everything the MCP tools serve is also available as plain GET routes — useful for `curl`, scripts, or agents without MCP support:
|
|
401
194
|
|
|
402
|
-
| Route
|
|
403
|
-
|
|
|
404
|
-
| `GET /lowdefy-docs`
|
|
405
|
-
| `GET /lowdefy-docs/{kind}`
|
|
406
|
-
| `GET /lowdefy-docs/plugins`
|
|
407
|
-
| `GET /lowdefy-docs/schema/{kind}/{type}`
|
|
408
|
-
| `GET /lowdefy-docs/examples/{type}`
|
|
409
|
-
| `GET /lowdefy-docs/content/{slug}`
|
|
410
|
-
| `GET /lowdefy-docs/search?q={query}
|
|
411
|
-
| `GET /lowdefy-docs/plugin-doc/{package}`
|
|
412
|
-
| `GET /lowdefy-docs/build-status`
|
|
413
|
-
| `GET /lowdefy-docs/
|
|
414
|
-
| `GET /lowdefy-docs/
|
|
415
|
-
| `GET /lowdefy-docs/
|
|
416
|
-
| `
|
|
417
|
-
| `GET /lowdefy-docs/
|
|
418
|
-
| `
|
|
419
|
-
| `
|
|
420
|
-
| `POST /lowdefy-docs/
|
|
421
|
-
| `POST /lowdefy-docs/
|
|
422
|
-
| `POST /lowdefy-docs/run-endpoint` | Execute an Api endpoint routine with a test payload and caller (needs `allowWriteRequests`; rejects return as data) |
|
|
423
|
-
| `GET/POST /lowdefy-docs/checkpoints` + `/revert` | Config-file checkpoints |
|
|
424
|
-
| `GET/POST /lowdefy-docs/state-checkpoints` + `/snapshot`, `/load` | State & data checkpoints |
|
|
425
|
-
| `POST /lowdefy-docs/restart` | Restart the dev server process (`{reason}` optional; then `build-status?wait=true` answers once it is back) |
|
|
195
|
+
| Route | Purpose |
|
|
196
|
+
| --------------------------- | -------------------------------------------------------------- |
|
|
197
|
+
| `GET /lowdefy-docs` | Overview and route index |
|
|
198
|
+
| `GET /lowdefy-docs/{kind}` | List all available types of a kind, e.g. `/lowdefy-docs/blocks` |
|
|
199
|
+
| `GET /lowdefy-docs/plugins` | Installed plugin packages and the types each provides |
|
|
200
|
+
| `GET /lowdefy-docs/schema/{kind}/{type}` | JSON schema for a type, e.g. `/lowdefy-docs/schema/blocks/Button` |
|
|
201
|
+
| `GET /lowdefy-docs/examples/{type}` | Example YAML for a block type |
|
|
202
|
+
| `GET /lowdefy-docs/content/{slug}` | A docs page as markdown, e.g. `/lowdefy-docs/content/operators/_get` |
|
|
203
|
+
| `GET /lowdefy-docs/search?q={query}`| Search the docs |
|
|
204
|
+
| `GET /lowdefy-docs/plugin-doc/{package}` | Markdown shipped inside a plugin package |
|
|
205
|
+
| `GET /lowdefy-docs/build-status` | Current build errors/warnings + recent browser runtime errors |
|
|
206
|
+
| `GET /lowdefy-docs/page-config/{pageId}` | Fully built page config, or its build errors |
|
|
207
|
+
| `GET /lowdefy-docs/screenshot/{pageId}` | PNG screenshot of the rendered page |
|
|
208
|
+
| `GET /lowdefy-docs/find/{id}?pageId=` | Locate where a page/block/request id is defined |
|
|
209
|
+
| `GET /lowdefy-docs/app-map` | Whole-app graph: pages, menus, connections, endpoints, agents |
|
|
210
|
+
| `GET /lowdefy-docs/inspect-state/{pageId}` | Live state/requests/eventLog of a running page (tab or headless) |
|
|
211
|
+
| `POST /lowdefy-docs/eval-operator` | Evaluate an operator expression against live page state |
|
|
212
|
+
| `POST /lowdefy-docs/run-request` | Execute a request with a test payload (read-only unless opted in) |
|
|
213
|
+
| `GET/POST /lowdefy-docs/checkpoints` + `/revert` | Config-file checkpoints |
|
|
214
|
+
| `GET/POST /lowdefy-docs/state-checkpoints` + `/snapshot`, `/load` | State & data checkpoints |
|
|
426
215
|
|
|
427
216
|
## Local plugins
|
|
428
217
|
|
|
@@ -432,7 +221,6 @@ Your project's own plugins (declared under `plugins:` in `lowdefy.yaml`) are inc
|
|
|
432
221
|
- Block schemas are derived from each block's `meta`, and connection/request schemas from the `schema` property on your connection and request definitions.
|
|
433
222
|
- Ship a `gallery.yaml` or `examples.yaml` next to a block in your plugin's `dist/blocks/{BlockName}/` and it is served by `lowdefy_get_examples`.
|
|
434
223
|
- A `README.md` or `docs/*.md` files in your plugin package are served by `lowdefy_get_plugin_doc`.
|
|
435
|
-
- Editing a local plugin (a package linked from your workspace) rebuilds the config, so a new or renamed type is defined and a build the plugin broke clears once it is fixed. When the plugin has server-side types (connections, requests, server operators, agents, websockets, notifications, auth) the dev server also restarts, so the new implementation is what runs; block, action and client-operator edits hot-reload through Vite without a restart. If the server still looks stale, call `lowdefy_restart` or `POST /lowdefy-docs/restart`.
|
|
436
224
|
|
|
437
225
|
## Docs for crawling agents
|
|
438
226
|
|