Lazyweb Deep Design Research
SkillDatabases & dataLets 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.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
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-boundupgrade_urlto 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-boundupgrade_urlto the user, then stop. Do not retry another data tool or fall back to web/manual output.- Successful
status: "locked_preview": relaydisplay_to_userverbatim (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:
- Author the report content as
.lazyweb/deep-design-research/{topic}-{date}/work/report-data.json(structured content, NOT HTML) - 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/ - Do NOT create
report.md,report.html, or any other report artifact by hand — the server renders the report - Do NOT write research content into a plan file
- 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 - 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)
- Ask the user if the research looks good
- If in plan mode, exit plan mode after the user confirms - the research is done
- Suggest next steps: "You can now use this research to inform your implementation,
ask
/lazywebto 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 parsedwork/report-data.jsonobject (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 viareferences/{name}. Lazyweb references embedded by absoluteimageUrlare 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; keepassets:[{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/VERSIONat skill start.
Handle the result:
{ ok: true, url }— the report is live. Show "Shareable link: {url} (unlisted - anyone with the link can view)", thenopen "{url}"in the user's browser (skipopenin a headless/CI/no-GUI environment and just print the link).{ ok: false, code: "REPORT_RENDER_ERROR", detail }—detailnames the missing or invalidreport_datafield (e.g.missing data.topic,bets must have 2-4 entries). Fix that field inwork/report-data.jsonand 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 (theerrorfield). 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_urlURL Lazyweb returns. - Locally saved screenshots (current-state, web captures, generated prototypes): a relative
references/{filename}path, with that file uploaded as anassetin 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(objectiveoptimizeorimprove)
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 screenshotslazyweb_find_similar- more results like a returned LazywebimageUrlor image payloadlazyweb_compare_image- visual search from animage_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 animage_url(spec:specs/image-upload-architecture.md)lazyweb_health- connectivity checklazyweb_render_report- render + host the finished report fromreport_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:
- Run
lazyweb-context-detect(onPATHwhen installed by setup; otherwise~/.lazyweb/repos/lazyweb-skill/bin/lazyweb-context-detect). Use its project/platform/stack output to bias theplatformfilter and captions. - 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:
- 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 fromevidence.jsonfor embedding. You may view at most the top ~10 candidate images before the final pick — never the whole corpus. - 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.pyagain towork/evidence-topup.json:lazyweb_find_similaron the 2-3 strongest results, passing each reference'simageUrlstring asimage_url,"limit": 5;lazyweb_compare_imageis 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) andevidence-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'analysisfields.
- Coverage honesty: if
coverage_summaryshows failed or low_coverage queries — even when the script exits 0 — carry that into the report's.corpusbanner 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
github.com/aboul3ata/lazyweb-skill
Related picks
Skill · thedaviddias
The pick for JavaScriptmodern-javascript-patterns
Skill · wshobson
The pick for JavaScriptpython-performance-optimization
Skill · wshobson
The pick for Pythonpython-pro
Skill · jeffallan
The pick for Pythonnewsletter-writer
Skill · cbrock84
The pick for Newsletternewsletter-management
Skill · manojbajaj95
The pick for Newsletter