Lazyweb Deep Design Research

SkillDatabases & data

Lets your agent design a brand-new product screen from scratch, producing a visual HTML report with prototype options.

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Lazyweb Deep Design Research skill

About this skill

INTERNAL create / greenfield backend. NOT a user-facing slash command, it is reached via `/lazyweb-design` with `objective=create`, which redirects here for designing a NEW product screen from scratch (no existing screen to ground on). Combines Lazyweb's screenshot database with web research and pr

What this skill tells your AI

The instructions your AI receives, as published by aboul3ata/lazyweb-skill in skills/lazyweb-design-create/SKILL.md and read by ahel’s review.

Evidence-backed design research that reads the user's current screen, names its frictions, forms 2-4 genuinely divergent redesign bets, and renders a visual-first HTML report where the recommended prototype sits side by side with the control.

People learn by seeing. Every claim in the report is carried by a large, legible visual; nothing important hides behind a click. Chrome stays quiet: no chip clutter, no legend tables, no explanatory paragraphs next to the proof.

MCP plan responses — check before the normal workflow

Inspect every data-bearing tool result before applying its normal search, render, or report schema:

  • MCP_PRO_REQUIRED: relay the server message and returned intent-bound upgrade_url to the user, then stop. Do not retry another data tool or fall back to web/manual output.
  • FREE_REPORT_DAILY_LIMIT: relay the server message and returned intent-bound upgrade_url to the user, then stop. Do not retry another data tool or fall back to web/manual output.
  • Successful status: "locked_preview": relay display_to_user verbatim (or the returned MCP text if that is all the client exposes), including the preview and upgrade links. It is terminal and contains no generated research; do not poll, render or assemble a report, retry another data tool, or fall back.

CRITICAL: Output Behavior

This skill produces FILES, not a plan. Regardless of whether you are in plan mode or not, ALWAYS:

  1. Author the report content as .lazyweb/deep-design-research/{topic}-{date}/work/report-data.json (structured content, NOT HTML)
  2. Embed Lazyweb references directly with their returned imageUrl/image_url; save only current-state and web-captured screenshots under .lazyweb/deep-design-research/{topic}-{date}/references/
  3. Do NOT create report.md, report.html, or any other report artifact by hand — the server renders the report
  4. Do NOT write research content into a plan file
  5. Render and host the report with lazyweb_render_report (see "Render and host the report" below) — this single call IS the deliverable; producing the report and hosting it are the same action, so there is nothing to skip
  6. After the render call returns, show the user a concise summary, the recommended bet, and the shareable link (the report lives only at that URL)
  7. Ask the user if the research looks good
  8. If in plan mode, exit plan mode after the user confirms - the research is done
  9. Suggest next steps: "You can now use this research to inform your implementation, ask /lazyweb to improve your current design, or start building."

The visible report is: Agent Instructions, Goal, Recommendation, and optional Inspo — in that order. Do not produce the older busy structure with key examples, findings, sources, broad recommendation lists, or long prose analysis sections.

The Recommendation is built like lazyweb-design's hypothesis engine, with screenshot evidence taking the role experiment evidence plays there: read the control, name its specific frictions, form 2-4 falsifiable and structurally divergent bets (Safe bet / Bold bet / Wild card — a thinking discipline, not visible chips), prototype each as a generated image, and carry the decision. When a current page or screenshot exists, render Control and the recommended prototype side by side in equal, height-locked frames with a ◀ ▶ variant switcher on the right frame so the user can flip through the other bets in place; runner-up bets also appear in a snap carousel of same-size cards. Prefer generated bitmap prototype images over hand-coded HTML mockups when image generation is available; use HTML/CSS only as a fallback or when the user asks for implementation-ready code. Generate prototype images in parallel at medium effort by default, or low effort when the user asks for speed/exploration.

Render and host the report (the single deliverable)

The report is rendered and hosted server-side. You author the report content as work/report-data.json, then call lazyweb_render_report ONCE. That call fills the canonical template on the server, validates it, hosts it at https://www.lazyweb.com/report/lazyweb/{id}/, and returns the shareable link. There is no local report.html to write, no separate publish step, and no token to read — producing the report and hosting it are the same action, so a finished report is always a shared report.

Call it once work/report-data.json and every references/ image exist. The report dir is $REPORT_DIR = .lazyweb/deep-design-research/{topic-slug}-{YYYY-MM-DD}.

Arguments:

  • report_data: the parsed work/report-data.json object (see "Author report-data.json" below).
  • assets: every file in $REPORT_DIR/references/ as { "name": <filename>, "b64": <base64 of the bytes> } — the control screenshot and each generated prototype image the report points at via references/{name}. Lazyweb references embedded by absolute imageUrl are NOT assets; only locally saved files. (Note: migrating these render assets off inline base64 to the presigned upload flow is Phase 2 — out of scope here; keep assets:[{b64}] as-is.)
  • report_skill: "deep-design-research".
  • idempotency_key: the report dir slug, e.g. deep-design-research/{topic-slug}-{YYYY-MM-DD}. Send the SAME value on every call for this report so a retry returns the same link instead of a duplicate.
  • version: the value you read from ~/.lazyweb/VERSION at skill start.

Handle the result:

  • { ok: true, url } — the report is live. Show "Shareable link: {url} (unlisted - anyone with the link can view)", then open "{url}" in the user's browser (skip open in a headless/CI/no-GUI environment and just print the link).
  • { ok: false, code: "REPORT_RENDER_ERROR", detail } — detail names the missing or invalid report_data field (e.g. missing data.topic, bets must have 2-4 entries). Fix that field in work/report-data.json and call ONCE more.
  • { ok: false, code: "REPORT_TOO_LARGE" } — the embedded screenshots are too large. Reduce their number/size and retry once.
  • any other { ok: false } — tell the user hosting failed and why (the error field). There is no local copy, so they need the link or the reason.

The server fills a fixed, render-tested template and rejects an incomplete report_data (missing fields → REPORT_RENDER_ERROR), so a partial or skeleton report can never be hosted — that replaces the old client-side contract gate. Never hand-render HTML or fall back to a local file.

Image references in report-data.json

You never write HTML — you only choose image src values in report-data.json:

  • Lazyweb references: the absolute imageUrl/image_url URL Lazyweb returns.
  • Locally saved screenshots (current-state, web captures, generated prototypes): a relative references/{filename} path, with that file uploaded as an asset in the render call.
  • Never use file:// URLs or absolute local paths (/Users/..., C:\...).

When to Use This

  • User wants to understand a design space before building
  • User needs competitive analysis for a feature
  • User asks "what are best practices for X"
  • User wants to see how the best apps solve a specific problem

When NOT to Use This

  • User just wants to see a few screenshots quickly -> route to lazyweb-quick-search
  • User has an existing design and wants to optimize or improve it -> route to lazyweb-design (objective optimize or improve)

Lazyweb MCP Setup

Use the hosted Lazyweb MCP tools at https://www.lazyweb.com/mcp for all Lazyweb database access.

Downloading or updating the skill pack, installing or configuring a client, and creating or reusing a bearer token are available to everyone without charge. Setup, health, and workflow discovery remain usable regardless of plan; real data-bearing MCP tool availability and usage limits depend on the account's persisted experiment assignment and plan.

Required MCP tools:

  • lazyweb_search - text search over mobile and desktop screenshots
  • lazyweb_find_similar - more results like a returned Lazyweb imageUrl or image payload
  • lazyweb_compare_image - visual search from an image_url (the control reaches it via the presigned upload flow; see "Send the control via presigned upload")
  • lazyweb_request_image_upload / lazyweb_resolve_image_upload - presigned upload for the control screenshot: request a { upload_url, key }, PUT the bytes, resolve to an image_url (spec: specs/image-upload-architecture.md)
  • lazyweb_health - connectivity check
  • lazyweb_render_report - render + host the finished report from report_data + reference images, returns the shareable link (the deliverable; see "Render and host the report" above)

Optional MCP tools:

  • lazyweb_search_ab_tests - mobile-only supporting experiment evidence for pricing, paywall, checkout, onboarding, and other growth/monetization screens when the live schema exposes it

Pass skill: "lazyweb-design-create" on every Lazyweb call. Include "skill": "lazyweb-design-create" in the arguments of each lazyweb_* tool call - for example {"query": "pricing page", "limit": 30, "skill": "lazyweb-design-create"}. This is optional analytics metadata; never drop or change a real argument for it. (Keep report_skill="deep-design-research" on lazyweb_render_report — that backend/report tag stays legacy; only the analytics skill slug moves to lazyweb-design-create.)

Also pass version: "<x.y.z>" on every call. Read ~/.lazyweb/VERSION once per session at skill start (e.g. cat "$HOME/.lazyweb/VERSION" 2>/dev/null || echo 0.0.0); fall back to "0.0.0" if the file is missing or unreadable — never block on this. Include "version": "<that-value>" in the arguments of every lazyweb_* tool call alongside the existing skill arg — for example {"query": "pricing page", "limit": 30, "skill": "lazyweb-design-create", "version": "0.4.5"}. Optional analytics metadata Lazyweb uses to track which skill-pack versions are running; never drop or change a real argument for it.

Also pass integrity verbatim on every call. Read it once per session at skill start (cat "$HOME/.lazyweb/INTEGRITY" 2>/dev/null). Pass that exact string as the integrity arg on every lazyweb_* tool call — it is an opaque install fingerprint; copy it verbatim and do NOT interpolate, edit, parse, or reconstruct it. If the file is absent, OMIT the integrity field entirely — never invent one. This is the field that tells Lazyweb your pack is current.

These are the current public gateway names. Backend/internal surfaces may also expose canonical tools such as search_screenshots, list_filters, vision_screenshots, and metadata_screenshots; prefer the lazyweb_* names in this skill. Use high_design_bar: true only when the live tool schema exposes it and the user asks for high-design-bar companies, premium examples, best-designed apps, or stronger visual-quality filtering. That filter is backed by companies.high_design_bar = true.

Before searching, verify MCP is available by listing tools and running lazyweb_health.

If a Lazyweb tool is refused as OUT OF DATE — the result has code: "skill_deprecated" / action_required: "upgrade" / do_not_fallback: true, or says your skill pack is below the required version — this is a HARD STOP, not a fallback case. Do NOT proceed in web-research-only or any degraded mode; that output is deprecated and ungrounded. STOP the task, tell the user they must upgrade, and have them run /lazyweb-update (or curl -fsSL https://www.lazyweb.com/install.sh | bash), reload the client, and retry. The design tools are now unified under /lazyweb-design.

If Lazyweb MCP is genuinely not installed or auth fails (a connection/auth error — NOT a version refusal): Tell the user: "Lazyweb MCP is not installed. Run curl -fsSL https://www.lazyweb.com/install.sh | bash, reload this client, then rerun this skill. Installing and receiving a bearer token do not require payment; real data-bearing MCP access and limits depend on your assigned experiment and plan. Keep the token in ignored local config." Then proceed with web research only - the skill still works, just without Lazyweb's database.

Browse Setup (run BEFORE any web capture)

LB=""
# Check the standalone Lazyweb checkout first
for _P in "$(pwd)/.lazyweb/repos/lazyweb-skill/browse/dist/browse" ~/.lazyweb/repos/lazyweb-skill/browse/dist/browse; do
  [ -x "$_P" ] && LB="$_P" && break
done
# Fall back to gstack browse
if [ -z "$LB" ]; then
  _ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
  [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && LB="$_ROOT/.claude/skills/gstack/browse/dist/browse"
  [ -z "$LB" ] && [ -x ~/.claude/skills/gstack/browse/dist/browse ] && LB=~/.claude/skills/gstack/browse/dist/browse
fi
[ -x "$LB" ] && echo "BROWSE_READY: $LB" || echo "NO_BROWSE"

Immediately after BROWSE_READY, set a real viewport — the daemon's default window can be arbitrarily small and silently produces unusable captures:

$LB viewport 1440x900

Use $LB screenshot --viewport <path> for viewport-window shots; the default screenshot is full-page.

If NO_BROWSE: Web screenshot capture is unavailable. Lazyweb results still work - just describe web examples in text without screenshots. To enable web captures, run: cd ~/.lazyweb/repos/lazyweb-skill/browse && ./setup

Workflow

0. Ground the search

Before searching, ground the work in what the user is building:

  1. Run lazyweb-context-detect (on PATH when installed by setup; otherwise ~/.lazyweb/repos/lazyweb-skill/bin/lazyweb-context-detect). Use its project/platform/stack output to bias the platform filter and captions.
  2. Clarify only what cannot be inferred. If platform is unknown, or the product/screen/outcome is unclear, ask the user ONE short clarifying question to pin down product/screen, mobile vs desktop, and the specific outcome.

1. Understand the research question

Pin down:

  • The specific screen, flow, or feature
  • The product type, audience, and platform
  • The design outcome the recommendation should improve

2. Capture current state (if applicable)

If the user is researching a specific page or app they are building, capture the current state:

  • Running dev server or URL available: use preview/browse tools to screenshot it
  • Mobile app: ask the user to provide a screenshot
  • General topic only: skip this step

Define the report directory FIRST (steps 2-7 write into it):

REPORT_DIR="$(pwd)/.lazyweb/deep-design-research/{topic-slug}-{YYYY-MM-DD}"
mkdir -p "$REPORT_DIR/references" "$REPORT_DIR/work"

Save as $REPORT_DIR/references/current-state.png. This image becomes Control in the side-by-side Recommendation comparison. Do not create a separate visible "Current State" section.

3. Read the control (required when a current state exists)

Before any searching or ideation, read the control the way lazyweb-design reads a paywall. Identify:

  • Components present: header, hero, value prop, proof, pricing, CTAs, trust signals, navigation, FAQ, footer — whatever the screen type implies
  • Layout pattern: single-column stack, hero + grid, comparison layout, dashboard shell, feed, wizard, etc.
  • Strategic moves: what the screen is trying to do — anchoring, social proof, demonstration, urgency, curiosity, authority, personalization
  • Audience and user state: who lands here and how warm they are
  • Named frictions: 2-5 specific, observable weaknesses of THIS screen ("proof arrives below the fold", "CTA copy is generic", "hero asserts value without showing the product"). Every later hypothesis must attack one of these by name.

If there is no current state (greenfield research), substitute a baseline read: the convention set the category expects, and which conventions the user's product can or cannot honor. Hypotheses then attack gaps between that baseline and the strongest references.

4. Identify competitors and adjacent companies

Think about two groups:

  • Direct competitors - apps that solve the same problem
  • Adjacent companies with great design - apps in related spaces known for excellent UX

5. Search Lazyweb (go deep — the corpus is the product)

Fast path (default): run the evidence script, not agent gatherers. A deterministic fetcher ships next to this skill: fetch-evidence.py (python3 stdlib only). Build the full Pass A + Pass B query plan as JSON first, then run it once — all queries fire in parallel (capped at 6 in-flight, 20s timeouts, one Retry-After-honoring retry on 429/5xx):

cat > "$REPORT_DIR/work/query-plan.json" <<'PLAN'
{"skill":"lazyweb-design-create","version":"<from ~/.lazyweb/VERSION>","queries":[
 {"id":"a1","pass":"A","tool":"lazyweb_search","args":{"query":"<screen/component>","platform":"desktop","limit":15}},
 {"id":"b1","pass":"B","tool":"lazyweb_search","args":{"query":"<underlying function>","platform":"desktop","limit":15}}
]}
PLAN
python3 "{skill-base-dir}/fetch-evidence.py"   --plan "$REPORT_DIR/work/query-plan.json"   --out  "$REPORT_DIR/work/evidence.json" || echo "FETCH_FALLBACK"

On success, work/evidence.json holds merged, same-company-deduped references (imageUrl + visionDescription verbatim) plus a coverage_summary, and work/evidence-summary.json holds a compact no-URL digest. Then:

  1. One selection + clustering pass (you, the main agent): READ ONLY evidence-summary.json (indices + truncated descriptions — a fraction of the tokens), select 12-20 references and form the 2-4 clusters, then pull just the selected indices' full records from evidence.json for embedding. You may view at most the top ~10 candidate images before the final pick — never the whole corpus.
  2. One bounded top-up round — ALSO through the script, never via raw MCP tool calls (the v3.4 timed run lost 12 minutes to MCP token dumps here). Write a second small plan and run fetch-evidence.py again to work/evidence-topup.json:
    • lazyweb_find_similar on the 2-3 strongest results, passing each reference's imageUrl string as image_url, "limit": 5;
    • lazyweb_compare_image is OMITTED from the fast path (measured: low yield). Only the agent-fallback path may use it, sending the control via the presigned image-upload flow (request -> PUT -> resolve -> image_url; see "Send the control via presigned upload" below, spec: specs/image-upload-architecture.md) — never inline base64. Read ONLY the script's stderr verdict line (TOPUP_SATURATED: / TOPUP: N attachable) and evidence-topup-summary.json — never the raw top-up file (its signed URLs are payload-hostile). Expect description-less near-dupes more often than not: budget at most 2 vision-verifications, and treat an empty yield as saturation confirmation (your corpus was already complete), not failure. When search_ab_tests returns 0 references, its prose learnings are in the queries' analysis fields.
  3. Coverage honesty: if coverage_summary shows failed or low_coverage queries — even when the script exits 0 — carry that into the report's .corpus banner when the selected corpus lands under 8 references or a whole pass came back thin.

Agent fallback (REQUIRED to keep working — do not remove): when the script exits non-zero, prints FETCH_FALLBACK, emits invalid JSON, or python3 is missing, gather via the Lazyweb MCP tools yourself instead: run the same Pass A/Pass B plan as batched agent tool calls — three roles (median mapper / edge hunter / web + control) dispatched as parallel subagents when the host has an Agent tool, sequential phases otherwise. Gatherer prompts MUST state: (a) the output directory already exists — use the Write tool only, never Bash/mkdir; (b) copy each returned imageUrl string VERBATIM — a reference without it cannot be embedded; (c) expansion results lacking a visionDescription are kept (top ≤5) as pending_vision entries for the main agent to vision-verify after the merge.

Text before image (hard rule, applies to every gatherer): select and rank references from TEXT — visionDescription, captions, coverage, warnings, similarity scores — before fetching or viewing ANY image. An image may be viewed only after its text fields qualify it for the report (or when vision-verifying an agent-described result). Viewing images first is the single biggest avoidable token-and-time cost in this phase.

Search discipline: never repeat an identical query; results are deterministic. Page deeper with offset and follow the response's pagination.next_offset. Read coverage and warnings on every response. On no_matches/low_coverage, use the closest result, strip the query to its core 2-6 word UI pattern, or note the coverage gap in the report. On company_not_in_library, use a suggested company or drop the filter.

Keep a running search log at $REPORT_DIR/work/search-log.json — append every query with its filters/offset as you run it (gatherers append to their own work/gatherer-{n}.json; the merge step consolidates). This is what makes a crashed run resumable and is the ground truth for "never repeat an identical query".

Run 6-10 searches minimum, split into two mandatory passes:

Pass A — map the median (2-4 searches). The in-category baseline: what everyone in the user's space does. This is what the Safe bet completes and what the Bold bet must NOT resemble.

{"query":"<specific screen/component>","limit":15}
{"query":"<screen type>","company":"<competitor>","limit":15}
{"query":"<screen type>","category":"<category>","limit":15}
{"query":"<different description of same thing>","limit":15}

Pass B — hunt the edges (4-6 searches, REQUIRED — never skip). Deliberately search OUTSIDE the obvious category and BELOW the screen-name level. This pass exists to feed the Bold and Wild-card bets; a corpus that only contains the median can only produce median recommendations.

{"query":"<the underlying FUNCTION, not the screen name — 'data visualization with gamification' not 'dashboard'>","limit":15}
{"query":"<same screen type>","category":"<deliberately unrelated category: Gaming, Entertainment, Music, Editorial...>","limit":15}
{"query":"<the persuasion mechanism itself, e.g. 'live activity feed', 'interactive product demo'>","limit":15}
{"query":"<a second unrelated category doing the same job>","limit":15}

Cross-pollination routing: finance → look at Gaming/Entertainment/Music; productivity → Fitness/Travel/Social; e-commerce → Education/Health; developer tools → Editorial/Games. The more distant the category, the more novel the transferable mechanism. Yield ranking from live runs: function-level and mechanism-level queries find the most usable outliers; screen-type + unrelated-category is the weakest shape (often low coverage) — run it last and drop it first when budget-constrained. While reading Pass B results, collect outliers: references that do something structurally unlike everything in Pass A. Outliers are the raw material of the Bold and Wild-card bets — note for each one the mechanism (what it DOES, not what it looks like), why it works in its home context, and what would have to adapt to transfer.

Then expand with lazyweb_find_similar on the 2-3 strongest results (highest similarity + best visionDescription fit) to pull in their visual neighbors. This is how the corpus gets from "three or four screenshots" to a real reference set.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
456
Forks
35
Last commit
Sep 2026

ahel review

  • K6low
    bundled executables the agent is told to run

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
lazyweb-design-create
Source
github.com/aboul3ata/lazyweb-skill