{"result":{"depiction_url":null,"edges":{"in_module":{"objects":[{"created":"2026-11-11T09:19:20Z","object_id":{"id":1457,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_development","title":"mod_development","uri":"https:\/\/zotonic.com\/id\/1457"},"seq":1}],"predicate":{"id":333,"is_a":["meta","predicate"],"name":"in_module","title":{"_type":"trans","tr":{"en":"In module"}},"uri":"https:\/\/zotonic.com\/id\/in_module"}},"refers":{"objects":[{"created":"2026-11-11T12:17:45Z","object_id":{"id":3183,"is_a":["text","documentation","reference","model"],"name":"doc_model_model_development_capture","title":"development_capture","uri":"https:\/\/zotonic.com\/id\/3183"},"seq":1000000}],"predicate":{"id":2409,"is_a":["meta","predicate"],"name":"refers","title":{"_type":"trans","tr":{"en":"Refers"}},"uri":"https:\/\/zotonic.com\/id\/refers"}},"subject":{"objects":[{"created":"2026-11-11T09:19:20Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-11-11T09:19:20Z","object_id":{"id":2563,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_frontend_developer","title":"Frontend developer","uri":"https:\/\/zotonic.com\/id\/2563"},"seq":2},{"created":"2026-11-11T09:19:20Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":3},{"created":"2026-11-11T09:19:20Z","object_id":{"id":2608,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_routing_and_redirects","title":"Routing and redirects","uri":"https:\/\/zotonic.com\/id\/2608"},"seq":4},{"created":"2026-11-11T09:19:20Z","object_id":{"id":2613,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_development_and_debugging","title":"Development and debugging","uri":"https:\/\/zotonic.com\/id\/2613"},"seq":5},{"created":"2026-11-11T09:19:20Z","object_id":{"id":2625,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_model","title":"Model","uri":"https:\/\/zotonic.com\/id\/2625"},"seq":6}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"export_revision":23,"id":3182,"is_a":["text","documentation","reference","model"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3182"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_model_model_development_tools","page_url":{"en":"https:\/\/zotonic.com\/docs\/3182\/development_tools","x-default":"https:\/\/zotonic.com\/docs\/3182\/development_tools"},"preview_url":null,"resource":{"version":8,"pivot_location_lat":null,"title":"development_tools","is_authoritative":true,"body":"<p>Inspect a running site&#39;s dispatch rules, template resolution, source, composition,\nand available model APIs. Combine this model with <a href=\"\/id\/doc_model_model_development_capture\" class=\"doc-reference doc-reference-model\"><code>model#development_capture<\/code><\/a>\nwhen conditional or lazy rendering needs runtime evidence.<\/p>\n<p>For local and remote workflows, see the\n<a href=\"..\/..\/..\/..\/doc\/guides\/llm-site-development.md\">LLM site development guide<\/a>.<\/p>\n<h2>Access<\/h2>\n<p>All endpoints require an administrator with <code>use mod_development<\/code> permission\nand a site environment of <code>development<\/code>, <code>test<\/code>, or <code>acceptance<\/code>. Production\nis denied, including trusted CLI calls. Read-only administrators can use these\ninspection endpoints.<\/p>\n<p>Inspection does not render pages, edit source, or deploy changes. Template\ncomposition may compile an indexed template to obtain its metadata.<\/p>\n<h2>Browser quick start<\/h2>\n<p>Authorized pages with the development head assets expose\n<code>window.z_development_tools<\/code>. Inspection requires neither a capture attachment\nnor a visible debug button.<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-javascript\">const tools = window.z_development_tools;\nconst route = await tools.dispatchTrace();\nconst template = await tools.template(&#39;page.tpl&#39;, &#39;article_resource_name&#39;);\nconst source = await tools.templateSource(&#39;page.tpl&#39;, &#39;article_resource_name&#39;);\nconst composition = await tools.templateComposition(&#39;page.tpl&#39;, &#39;article_resource_name&#39;);\n<\/code><\/pre>\n<p>All methods return promises containing the model result. Model errors reject\nwith <code>error.code<\/code>; transport failures also reject.<\/p>\n<table class=\"table\"><thead><tr><th>JavaScript method<\/th><th>Result<\/th><\/tr><\/thead><tbody><tr><td><code>dispatch()<\/code><\/td><td>Active dispatch rules.<\/td><\/tr><tr><td><code>dispatchTrace(path?)<\/code><\/td><td>Dispatch trace for a local path; defaults to <code>location.pathname<\/code>.<\/td><\/tr><tr><td><code>template(name, id?)<\/code><\/td><td>Winning template and indexed override candidates.<\/td><\/tr><tr><td><code>templateSource(name, id?, {candidate}?)<\/code><\/td><td>Selected candidate&#39;s metadata and UTF-8 source.<\/td><\/tr><tr><td><code>templateComposition(name, id?, {candidate}?)<\/code><\/td><td>Selected candidate&#39;s inheritance, local blocks, and literal includes.<\/td><\/tr><tr><td><code>templates({prefix, offset, limit}?)<\/code><\/td><td>Paginated indexed template names and winning locations.<\/td><\/tr><tr><td><code>modules()<\/code><\/td><td>Active modules and priorities.<\/td><\/tr><tr><td><code>models({prefix, offset, limit}?)<\/code><\/td><td>Paginated available models and exported callback methods.<\/td><\/tr><tr><td><code>modelDocumentation(name)<\/code><\/td><td>Model documentation, availability, transport patterns, and incomplete GET-path hints.<\/td><\/tr><\/tbody><\/table>\n<h2>Template selection and source<\/h2>\n<p>Use relative indexed template names, never filesystem paths. The optional <code>id<\/code>\nis a resource ID or name and applies the same category selection as <code>catinclude<\/code>.\nLookup returns the resolved <code>name<\/code>, winning <code>filepath<\/code>, and <code>candidates<\/code> in module\npriority order. Lower numeric priorities win.<\/p>\n<p>Source and composition accept a zero-based <code>candidate<\/code> position from that list.\nOmit it for the winner; pass <code>undefined<\/code> for the resource when selecting a candidate\nwithout category lookup:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-javascript\">const current = await tools.templateSource(&#39;page.tpl&#39;);\nconst next = current.candidates.find(c =&gt; c.candidate === current.candidate + 1);\nif (next) {\n    const parent = await tools.templateSource(current.name, undefined, {\n        candidate: next.candidate\n    });\n}\n<\/code><\/pre>\n<p>Use the next candidate to follow <code>{% overrules %}<\/code>. Each request resolves the\nindex afresh. Source results include <code>source<\/code>, <code>candidate<\/code>, <code>module<\/code>, <code>priority<\/code>,\nand <code>winner_filepath<\/code>; <code>filepath<\/code> identifies the file actually read. Source\nreading performs no rendering or compilation and is limited to 1 MiB of UTF-8.<\/p>\n<h2>Static composition<\/h2>\n<p>Composition uses compiler metadata and may compile the selected file. It does\nnot render templates or evaluate runtime inheritance arguments.<\/p>\n<table class=\"table\"><thead><tr><th>Field<\/th><th>Meaning<\/th><\/tr><\/thead><tbody><tr><td><code>inheritance<\/code><\/td><td><code>type<\/code> is <code>none<\/code>, <code>extends<\/code>, or <code>overrules<\/code>; a resolved parent is in <code>target<\/code>, or lookup failure in <code>error<\/code>.<\/td><\/tr><tr><td><code>blocks<\/code><\/td><td>Names defined in this file, not inherited or effective blocks.<\/td><\/tr><tr><td><code>includes<\/code><\/td><td>Literal references with <code>template<\/code>, <code>line<\/code>, <code>column<\/code>, <code>method<\/code>, and <code>is_catinclude<\/code>.<\/td><\/tr><tr><td><code>analysis<\/code><\/td><td><code>static<\/code>.<\/td><\/tr><tr><td><code>blocks_scope<\/code><\/td><td><code>local<\/code>.<\/td><\/tr><tr><td><code>includes_scope<\/code><\/td><td><code>literal_references<\/code>.<\/td><\/tr><\/tbody><\/table>\n<p>Include methods are <code>normal<\/code>, <code>optional<\/code>, or <code>all<\/code>. Dynamic include names,\nconditional choices, and resource category selection at include call sites are\nnot resolved. Follow parent targets and include names with further lookups;\ntrack visited files to avoid cycles. A missing parent is reported in\n<code>inheritance.error<\/code>; compilation errors fail the request.<\/p>\n<h2>Discover model APIs<\/h2>\n<pre class=\"notranslate\"><code class=\"notranslate language-javascript\">const models = await tools.models({prefix: &#39;rsc&#39;, offset: 0, limit: 50});\nconst api = await tools.modelDocumentation(&#39;rsc&#39;);\n<\/code><\/pre>\n<p>Model names omit <code>m_<\/code>. Discovery includes core and active-site models, honoring\nthe site&#39;s effective resolution and core-model precedence. Entries identify\n<code>name<\/code>, <code>erlang_module<\/code>, owning <code>module<\/code>, <code>filepath<\/code> when available, load\navailability, and exported <code>get<\/code>, <code>post<\/code>, or <code>delete<\/code> callback methods.<\/p>\n<p>Documentation comes from BEAM metadata with a source fallback. The result\nincludes Markdown <code>documentation<\/code>, <code>documentation_available<\/code>, <code>methods<\/code>,\n<code>mqtt_topic<\/code>, <code>http_url<\/code>, and <code>path_hints<\/code>. No model callbacks are invoked to\nprobe supported arguments or schemas.<\/p>\n<p><code>path_hints_complete<\/code> is always false. Hints can omit delegated or dynamic GET\npaths and do not describe POST\/DELETE schemas. A segment named <code>any<\/code> is a\nplaceholder. Exported callbacks and path hints do not grant permission to call\nthem. Unknown or inactive model names cannot be used to inspect arbitrary Erlang\nmodules or files.<\/p>\n<h2>HTTP and MQTT reference<\/h2>\n<p>All operations use GET. HTTP paths start with\n<code>\/api\/model\/development_tools\/get\/<\/code>; supply arguments as query fields. Browser\nMQTT topics start with <code>bridge\/origin\/model\/development_tools\/get\/<\/code>; supply\narguments as the payload object.<\/p>\n<table class=\"table\"><thead><tr><th>Path<\/th><th>Arguments<\/th><\/tr><\/thead><tbody><tr><td><code>dispatch\/list<\/code><\/td><td>None.<\/td><\/tr><tr><td><code>dispatch\/trace<\/code><\/td><td><code>path<\/code>: local absolute URL path, including any language prefix.<\/td><\/tr><tr><td><code>template\/lookup<\/code><\/td><td><code>name<\/code>, optional resource <code>id<\/code>.<\/td><\/tr><tr><td><code>template\/source<\/code><\/td><td><code>name<\/code>, optional <code>id<\/code> and <code>candidate<\/code>.<\/td><\/tr><tr><td><code>template\/composition<\/code><\/td><td>Same selection as source.<\/td><\/tr><tr><td><code>templates<\/code><\/td><td>Optional <code>prefix<\/code>, <code>offset<\/code>, <code>limit<\/code>.<\/td><\/tr><tr><td><code>modules<\/code><\/td><td>None.<\/td><\/tr><tr><td><code>models<\/code><\/td><td>Optional <code>prefix<\/code>, <code>offset<\/code>, <code>limit<\/code>.<\/td><\/tr><tr><td><code>model\/documentation<\/code><\/td><td><code>name<\/code> without <code>m_<\/code>.<\/td><\/tr><\/tbody><\/table>\n<p>Pagination defaults to an empty prefix, offset 0, and limit 50. Limits range\nfrom 1 to 200; offsets must be nonnegative. Dispatch tracing stays within the\nselected site and does not render its controller. Erlang tuples in dispatch\nresults become JSON arrays.<\/p>\n<p>HTTP JSON and MQTT response payloads use <code>{status: &quot;ok&quot;, result: ...}<\/code> or\n<code>{status: &quot;error&quot;, error: ...}<\/code>. Common errors are:<\/p>\n<table class=\"table\"><thead><tr><th>Error<\/th><th>Meaning<\/th><\/tr><\/thead><tbody><tr><td><code>eacces<\/code><\/td><td>Missing administrator\/module access or unsupported environment.<\/td><\/tr><tr><td><code>badarg<\/code><\/td><td>Invalid path, template name, selector, or pagination.<\/td><\/tr><tr><td><code>enoent<\/code><\/td><td>Missing resource, template, candidate, source file, or model.<\/td><\/tr><tr><td><code>too_large<\/code><\/td><td>Template source exceeds 1 MiB.<\/td><\/tr><tr><td><code>invalid_utf8<\/code><\/td><td>Template source is not valid UTF-8.<\/td><\/tr><tr><td><code>unavailable<\/code><\/td><td>A discovered model implementation cannot be loaded.<\/td><\/tr><\/tbody><\/table>\n<h2>CLI<\/h2>\n<p>Run from the server checkout, locally or through SSH:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-sh\">bin\/zotonic inspect mysite dispatch\nbin\/zotonic inspect mysite dispatch-trace \/nl\/news\/example\nbin\/zotonic inspect mysite template page.tpl article_resource_name\nbin\/zotonic inspect mysite templates _article\nbin\/zotonic inspect mysite modules\n<\/code><\/pre>\n<p>These CLI operations do not compile or render templates. Source, composition,\nand model documentation are available through JavaScript, HTTP, and MQTT.<\/p>","slug":"development_tools","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"e2046c8ea94bd263d9363bcb092fce3b0959f86e431c3e5a4bebf44f4c3e3eab","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":322,"is_a":["meta","category"],"name":"model","title":"Models","uri":"https:\/\/test.zotonic.com\/id\/322"},"doc_source_path":"apps\/zotonic_mod_development\/src\/models\/m_development_tools.erl","publication_start":"2026-11-11T09:19:20Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/apps\/zotonic_mod_development\/src\/models\/m_development_tools.erl","pivot_location_lng":null,"doc_source_kind":"model","name":"doc_model_model_development_tools","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2026-11-11T09:19:20Z","uri":null,"doc_status":"current","is_dependent":false,"erlang_app":"zotonic_mod_development","publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"8e6aad17c4d86dee983db46a656ed6f6a930bcbb\n","erlang_module":"m_development_tools","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-11-11T14:07:16Z","title_slug":"development_tools"},"uri":"https:\/\/zotonic.com\/id\/3182","uri_template":"https:\/\/zotonic.com\/id\/:id","version":23,"websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3182"}},"status":"ok"}