Skip to content
LazyFrog

Seeing your work

How your AI checks its work on LazyFrog: screenshots, trying pages in a real browser, design checks and reading what your app returns.

  • Press it, don't only look at it. preview_try opens the preview in a clean browser and runs your steps: click, type, select, press, scroll, wait, expect (is this on the page now?), media (is each audio and video's time really moving, and at what volume?) and screenshot. Name things as a visitor sees them (text), or use selector. Anything people press gets tried on a phone (viewport: "mobile", the default) before you say it works; a screenshot of a button isn't proof it does anything. Each step says what happened; media with no sound moving means the player doesn't play, whatever its button shows. It changes the preview's data as a visitor would, and never the live site. It is a browser: it hears nothing and isn't a real phone, so say what you tried and ask the user to try the rest.
  • Every project has a preview address, https://p-<id>.lazyfrog.app (project get shows it; project create returns it). It always shows your current work, live, so give it to the user and they can watch the app in their browser as you build. It is unguessable and marked noindex. If the user wants it private, project settings with preview_password asks visitors for a password; rotate_preview_url gives it a new address. Never put it in the site's own files (a share image, a canonical link, a sitemap): use the live address or a path; publishing names the files that still carry it. On the live site, a robots.txt you write is served after a few comment lines Cloudflare adds about AI use; without one, only those show.
  • A sleeping preview wakes when someone visits it (a short "waking up" page) and sleeps after 15 minutes without visits or tool calls. What a page does by itself doesn't keep it awake or wake it: an open tab's connections (the dev server's hot reload, a WebSocket, an event stream) count only when they open, a reconnect to a sleeping preview gets 503 with Retry-After, and a page that reloads itself shows "Preview asleep" and wakes it once the tab is looked at. Reading a project (project_read get) never wakes it either: a sleeping preview is reported asleep.
  • Check the app yourself with http_get (any path, against the running app; http_request for other methods and a body) and preview_screenshot (an image of a page, desktop or mobile).
  • Browser errors. preview_screenshot and design_check open the page in a clean browser (no extensions, a fresh profile) and list what went wrong there under "Browser errors in a clean browser": uncaught errors, console errors and the app's own files that failed to load (include_warnings: true adds console warnings), or "none". Fix what it lists like any other bug. The preview runs the app's development server, so it shows the framework's developer overlay (the error box over the page) and development-only warnings; the live site doesn't show the overlay to visitors.
  • When the person reports an error from their own browser, check it with a screenshot of that page first. If the clean browser shows nothing and the error mentions things the code never wrote (attributes such as data-lastpass-*, data-gr-*, data-1p-*, cz-shortcut-listen, or elements the code doesn't render), tell them in plain words: it's a browser extension on their side (a password manager, a spell checker) adding to the page; visitors on the live site don't see the overlay; a private window with extensions off shows the page without it. Change nothing in the code. Never sprinkle hydration-warning suppression (suppressHydrationWarning and the like) to hide it. A real hydration mismatch, one the clean browser shows too, comes from the code: a time or date, a random value, the locale, or invalid nesting (a <div> inside a <p>, a link inside a link). Fix it in the code so the server and the first render in the browser agree (render the changing value after the page has loaded, fix the nesting).
  • Publishing puts the preview live at https://<slug>.lazyfrog.app (see Publishing below).
  • exec runs commands as the project's user in /workspace. Default timeout 60 s (max 300); use background: true for longer work (up to timeout, default an hour) and follow it with the job tool. Long output keeps its end: send it to a file and fs_read it for all of it. ImageMagick (magick) and ffmpeg are installed, e.g. for photos the user brings: magick in.jpg -auto-orient -strip -resize '1600x1600>' -quality 72 out.webp. For text on an image use an installed font (magick -list font: the URW set, such as NimbusSans-Regular); a missing one only warns and the image still comes out, in a fallback. Anything a command leaves running is stopped when it finishes: servers belong in services.json. Commands share the sandbox's memory with the database and services (768 MB on Free): a command that would use more than what is left is stopped ("Stopped: the command used more than N MB"), and they keep running; work in smaller batches or stream instead of loading everything at once. A commit (its secret scan) or a publish stopped the same way fails with workspace_out_of_memory (see When something fails): change course, don't repeat it. Free workspaces are small, but on Free and Hobby a command gets extra room while it runs: a foreground exec (not background), git and project_scan have 512 MB more than the plan's memory for their run, taken back after, so a commit, an install, a type check or a build usually fits beside the dev server: don't stop the dev server first. When the node is busy a command runs without it, and the result says so ("the node is busy, so this command had no extra room"): try again in a few minutes. Run one heavy thing at a time (not project_scan, design_check or deploy preflight while a build, a test run or a second dev server runs), and prefer one page at a time for design_check. These checks take their turn, and when one fails the way a starved app does it is tried again by itself (after a big service restarts, when the workspace is nearly full). If it still fails it says why: the workspace short of memory (on Free that is its size, not a fault in the app), a page that didn't load (look at it with http_get and logs_tail), or a page that kept LazyFrog's checking browser busy or crashed it (it draws without a graphics card; try one page at a time, preview_screenshot meanwhile). Tell the user what was skipped and go on. A build on Free (it has no deploy preflight) that still runs out of memory with the extra room: stop the dev server for the build (service stop name "web"), run the build with exec again, and service restart it when the build is done; meanwhile the preview says the site has stopped.

For your AI: this page as Markdown · llms.txt