Knowledge base74 entries
Knowledge base
Common pitfalls, recurring AI-agent misconceptions, API misuse and their resolutions. Each entry is an authoritative reference you can link to when the same issue comes up again.
AI agents and the CLI 6
ClarificationConnect an AI assistant to Docly with MCPAI assistants such as Claude and ChatGPT connect to Docly through one MCP address, https://cloud.docly.net/mcp. On the consent page you choose what the…Best practiceHow an AI agent should use the docly CLIPoint an AI agent at this article before it changes a Docly site with the docly CLI. It lists no commands: running docly with no arguments prints the complete…Best practiceSet up AI agent instruction files for a workspaceAn agent instruction file's job is to point, not to teach: make reading the knowledge base mandatory before and after every task, then map the developer…Best practiceSign in to the docly CLI through the Docly cloudSign in with plain docly login, which goes through the Docly cloud (cloud.docly.net). The cloud reaches every workspace controller; a controller's own address…MisconceptionUse a docly CLI working copy instead of gitDocly has no git service: there is no git remote to clone from or push to. A Docly workspace is the live application, not a working copy. When you want a local…Best practiceWork safely on a live siteOn Docly the site's folder is production - no git, no staging, no build step - so pointing an AI agent straight at a live site is extremely productive and…
Templates and pages 20
Best practiceBuild client UI as structured web componentsWhen a client-side Docly solution grows beyond a single page, structure the UI as native Web Components (custom elements) instead of one large script that…Best practiceCache-busting bundles with assetUrlStatic files (images, CSS, JS) are served with a one-year max-age, so an unchanged bundle URL keeps serving stale JS/CSS to returning visitors long after you…PitfallDo not build file and image URLs by handlinkImage and linkFile now cover every linking case, including a file stored on another document, so there is no longer a reason to assemble the four-segment…PitfallgetFiles returns every file in the folderdocly.getFiles(folder) returns every file in the folder – documents, but also .hash files (redirects, helpers) and uploaded files such as SVG icons. A listing…ClarificationGive linked images SEO-friendly filenamesWhen you link an embedded image through Docly's scaling URL, the last path segment — the "virtual name" — becomes the image's public filename but is ignored…PitfallHash expressions do not escape HTMLTemplate output is verbatim. A #name# expression and a write() call both emit the value exactly as stored, and Docly performs no HTML escaping anywhere in that…PitfallHash files are cachedA hash page is rendered once per URL and the HTML is served to every visitor after that - on a publication with login, to every logged-in user. A page…PitfallOmit file extensions in linksDocly serves every page at a clean, extensionless URL and resolves the underlying file by name, so internal links must omit the .html and .hash suffix. A link…Best practiceOrganize pages and API endpoints into topic foldersDropping every page into one folder, or every endpoint straight into #/API/, produces a long, flat, unbrowsable list and flat, meaningless URLs as a site…Best practiceRedirect a moved page with a hash fileWhen a page moves for good, keep the old URL alive with a file named after the old path plus .old - for /tjenester/Salgsportaler that is…Bugrequest.completeUrl contains unencoded spacesFixed in production on 22 August 2026: request.completeUrl is now slugified like encodedUrl, so it no longer contains spaces. The request object carries eight…PitfallSocial share images must be JPEG or PNGog:image and twitter:image must point at a .jpg or .png, even when every visible image on the page is WebP or AVIF. A meta tag carries exactly one URL: there…PitfallTemplate operators differ from JavaScript in compatibility modeA .hash page runs in compatibility mode unless the site turns it off. In that mode Docly's older template operators live on top of JavaScript, and four of them…PitfallTest layouts in real viewportsResizing the browser window or using devtools device emulation checks one width at a time, and scrollable frames hide overflow that overflow-x:hidden clips…PitfallTwo hash expressions cannot be adjacentA doubled hash is the escape for a literal hash, so two hash expressions cannot touch. Write them back to back and the first one never terminates: the parser…PitfallUnresolved names in hash expressions render emptyA #name# expression in a hash file that resolves to nothing renders as an empty string. Nothing is thrown and nothing is logged — unlike JavaScript, where…Best practiceUse a scratch hash file to test Docly functionsA new .hash file is live the moment you save it and can print anything the server computes, so a throwaway scratch page is the cheapest way to answer a…ClarificationUse AVIF and WebP image formatsYou keep uploading JPEG/PNG as before; Docly converts on serving, and the file extension on the display name in the image URL decides the output format…Best practiceUse master pages for shared layoutWhen several pages or display templates share the same layout — header, footer, navigation, common CSS/JS — define a single master page (e.g. #/master.hash)…PitfallWrite fails after process in the same code blockOnce process() has run inside a #{ }# code block, a later write() call in that same block fails with "'write' method call failed with error 'Object reference…
API scripts 9
PitfallCheck access on the document you writeAn endpoint that checks access against one reference the caller sends (a folder, a Guid, metadata) and then writes to another reference the caller also sends…PitfallKeep private data under the # folderFiles in a published folder are reachable by their path, and a .docly document there is rendered by any display template for its schema. To keep data out of…ClarificationLinks in markup an API returns do not get the mount pathDocly adds the site's mount path to links that start with "/" in pages it renders, but not to markup an API script returns: HTML that comes back inside a JSON…ClarificationPath traversalDocly's filesystem functions reject ".." and "\", so classic ../ traversal cannot escape a folder. But every path is absolute from the site root and can reach…Best practicePublish folders and documents from API scriptsAn API script can publish folders and documents inside its own site with docly.publishFolder and docly.publishDocument, list the domains it may use with…MisconceptionReading query and form fields in API callsDocly API endpoints (#/API/*.js) do not receive an Express-style request object — input arrives via auto-bound function parameters and the globals query (URL…By designRequest bodies are limited to 30 MBA request to a published site - an API call or a form post - may carry at most 30,000,000 bytes; a larger body is refused with HTTP 413 before your script…By designSome docly functions exist only in API scriptsFunctions that write, send, call out or reveal workspace details are registered only for scripts under #/API/. In a .hash page, a display template or a master…Best practiceState-changing API endpoints must require POSTAn #/API/ endpoint that changes something - saveFile, deleteFile, sending mail, writing a document - runs just as willingly on a GET as on a POST unless the…
Security and access 3
PitfallProbes for .git and other flagged URLs count against your IPRequests for paths that scanners look for - .git, .claude, .vscode and the other tool folders, and flagged URLs such as wp-login.php or .env - are treated as…ClarificationShip secure user access fast: let Docly handle login, you handle the permissionsSkip the authentication tax — let Docly's built-in login handle passwords, resets, sessions, 2FA and threat protection for you (enterprise-grade security in…Best practiceUse the site router for your own sign-in and API tokensTo let other systems call a site with a token, or to sign people in with your own provider instead of a Docly account, publish the folder without sign-in and…
Site configuration and publishing 13
PitfallA folder takes precedence over a file with the same nameIf a folder and a file share a name (Foo.hash and the folder Foo), the folder wins: /Foo answers 301 to /Foo/, which renders the folder's index.hash, and the…Best practiceBuild a multi-module solution on one data folderA Docly solution with a public site, an admin application and a customer or member area is one workspace with one data folder, published once per module, where…ClarificationConfigure site settings and inherit them from the appA site's settings (images, security, headers, minify, hashjs and login) are grouped in sections. Each section can be its own file in the # folder, such as…Best practiceConvert an existing website to DoclyConverting an existing website to Docly has three obligations that hold simultaneously: the technique is rebuilt to Docly conventions rather than copied, the…MisconceptionDo not create a # folder inside an appAn app — a folder of type Docly App, formerly called a publish template — is itself the # namespace for the sites that use it, so a path the documentation…Best practiceKeep index.hash out of content foldersindex.hash is a fallback-resolved file: a single #/Folder/index.hash renders the listing for every folder, and #/Root/index.hash is served at the site root as…Best practiceOptimize page performanceWhen a Docly page scores poorly on PageSpeed Insights, use Claude Code and the Claude Chrome plugin to diagnose which bottleneck actually applies before fixing…Best practicePut configuration and secrets in the Config document#/Config is the standard location for site configuration in Docly: a schema-bound document in the #/ tree, which is never served over HTTP, is editable through…PitfallPut shared security headers in the template headers.jsonTo give every site that uses an app the same security headers (CSP and the rest), put them in the app: in headers.json in the template's root, or in the…PitfallSeparate code from content for non-developer usersWhen non-developer users will administer data in a Docly solution, move display assets (index.hash, shared CSS/JS, masters, partials) into #/Root and #/Folder…ClarificationSet a site's security level in site.jsonThe "security" section of a site's settings (#/security.json, or "security" in #/site.json, inherited from the app) decides which visitors must pass a…ClarificationSort folder contents by a custom fieldAdd a CustomColumns entry with Sorting set to "Sortable" to a folder's .docly properties and the folder view gets drag-and-drop ordering: dragging a row…Best practiceStart new sites in strict JavaScript modeStart every new site in the strictest mode: "hashjs": { "compatibilityMode": false } in the workspace's own #/site.json, and Modern syntax ticked on every…
Images 2
PitfallRestrict and register image sizesThe scaled image URL (/foto.jpg/1200x800x0/navn.jpg) is open by default: every unique size is a cache miss with heavy scaling and a new cache file on disk. A…MisconceptionScale and convert images in DoclyDocly scales and converts images on serving, but the URL is not /image.jpg/WxHxM/name.webp — it is /image.jpg/<embeddedId>/WxHxM/name.webp. Every uploaded file…
Schemas and documents 8
PitfallChapter fields do not render unless Expand is trueA chapter renders its child fields only when Expand is true. With Expand false the heading appears alone and the fields are silently absent from the schema…PitfallCreating new docly filesCreate a new .docly with the docly CLI: push it from a working copy, or run docly put <path> <file> --create. Both send the whole file in one request, and the…Best practiceGive folders a folder schema for their own page and settingsA folder's own page text and its menu fields belong on the folder, in a folder schema – not in helper documents (Overview, Index) placed inside the content…Best practiceKeep images out of rich text fieldsImages belong in image fields on the document (or folder) that shows them, rendered by the template with linkImage/linkFile – not as <img> tags inside a rich…PitfallRenaming a schema field does not migrate documentsRenaming a field in the schema designer updates the editor and the generated form, not the documents already saved - those keep the old key. Server-side code…Best practiceStore repeating rows in a table fieldStore a repeating list of rows in a schema by adding a Table field: it defines an Array key and Columns, and each record holds an array of row objects keyed by…ClarificationThe nearest schema wins when two schemas share a nameA document finds its schema by name, searching upward from its own folder: the schema on the nearest level wins. Among several schemas with the same name on…ClarificationWhich documents keep a version historyA document gets a new version on every save when its schema has EnableVersioning turned on and the workspace's subscription includes Revisions. The platform…
Forms 2
ClarificationHow a form submission is deliveredA form with an id and data-attributes is submitted by Docly itself: the submission is mailed to the workspace owner, data-smtp only chooses the SMTP…Best practiceProtect every form with TurnstileEvery form in Docly is protected with Cloudflare Turnstile - all of them. Use the built-in form submission: Docly mails every submission to the workspace owner…
Services 2
PitfallA site's own Services.json applies to every publication of the folderA site's own #/Services.json lives in the site FOLDER, not in one publication, so every publication of that folder picks it up — including publications on a…Best practiceRun a service when a file changesEvents in #/Services.json run a script in #/Services/ when a file on the site is created, changed or deleted. Changes are debounced and batched, the script…
JavaScript 9
PitfallA request starts with the invariant cultureFormatting runs under the invariant culture until the request sets one. docly.format(1234.5, "C") produces the generic currency sign, not a local one, and a…PitfallBlank numeric fields parse to NaN not zeroparseInt and parseFloat follow the ECMAScript spec: empty or non-numeric input returns NaN, not 0. A blank stored field is therefore a live source of NaN, and…PitfallDate objects carry both CLR and JavaScript membersA Date in HashJS answers to both the CLR and the JavaScript API on the same instance. The two disagree about the month: .Month is 1-based and .getMonth() is…BugDate parse and UTC return an object not millisecondsFixed in production on 29 September 2026: Date.parse and Date.UTC now return a number of milliseconds, and Date.parse reads ISO 8601 strings with Z, an offset…BugDates are saved as UTC and shown in local timeChanged in production on 23 October 2026: HashJS writes every date as toISOString - UTC, ending in Z - in JSON.stringify, saveJson, saveFile and API responses…MisconceptionDocly JavaScript is not NodeDocly's server-side JavaScript is HashJS, Docly's own engine written in .NET — not Node. There is no npm, no package.json, no node_modules, and no working…ClarificationFile reads are remembered for one requestWithin one request (or one service run), Docly looks up each file path once: getFile, getJson, include, import, load, fileExists and the include/master…PitfallTags are stored as search wordsA tag is not stored the way you type it. Docly puts it through the same term splitter as the full text index, so it is lower cased and split into single words…PitfallUse tilde paths in JavaScriptHardcoded leading-slash paths in JavaScript break the moment the app is published under a subfolder. On publish, Docly rewrites href and src attributes in…