| name | friction-report |
| description | Invoke at the end of every dev session, including when the user signals they're wrapping up. Scans the conversation for framework friction and drafts a report if any was found. Silent exit otherwise. Don't defer to later.
|
friction-report
End-of-session friction reporter. Scans the conversation you just had for build failures, doc gaps, SDK surprises, misleading errors, and training-data fallbacks. If anything worth reporting was found, drafts a structured report for human review. If the session was clean, exits silently.
No buffer, no per-turn tracking, no initialization step. Your conversation history is the source of truth.
When to run
- At the end of a dev session — when the user says "done", "thanks", "that's it", or when the task is clearly complete
- When the user explicitly asks: "report your friction", "what friction did you hit?", "give me the friction report"
- When the harness invokes this skill by name
If the user explicitly invoked the friction-log skill during this session, do not run — that skill already produced a detailed log.
Payload
Matches the same schema the visualizer validates. All top-level fields:
schema_version — always 1.
framework — what was being used (e.g. next, vite, remix). Required.
framework_version — exact version from package.json or CLI. Required.
summary — one sentence, biggest pain point. No user prompt verbatim, no code. Required.
model — your model id (e.g. claude-opus-4-7). Optional.
harness — what you're running in (e.g. VS Code agent, Claude Code). Optional.
scaffold_flags — flags used when scaffolding (e.g. ["--typescript", "--app"]). Optional.
build_count — how many builds ran during the session. Optional.
cumulative_build_ms — total build time in ms. Optional.
friction_points[] — each one has:
severity: red (blocked/broken) or yellow (extra steps/guesswork). Do NOT include greens.
title: one-line description, ≤200 chars.
expected: what you thought would happen. Strongly recommended, not optional in practice — without it, the report can't be reproduced.
actual: what actually happened. Strongly recommended, include the full causal chain when one symptom was caused by a separate upstream mistake (e.g. "page omitted Suspense because feature pre-wrapped its own, contradicting the architecture skill").
resolution: how it was fixed, or "unresolved". Strongly recommended.
source_tag: one of agents.md, docs, url, web search, training data, error output, sandbox, skill.
file_kind: what kind of file (e.g. route handler, next.config). Never an absolute path. Optional.
redacted_snippet: one redacted line of error output, ≤200 chars. Optional.
action_items[] — each one has:
bucket: docs, framework, or research.
title: what should be fixed or investigated.
context: the specific friction that led to this item, including upstream causes when relevant.
A friction report with only a title and a one-line action_items[].title is a placeholder, not a report. Fill in expected, actual, and resolution for every point. If a session had multiple frictions (e.g. one wrong stack trace + one architecture violation that caused it), file them as separate points and reference each other in actual.
Sanitize. Strip anything identifying the user, their project, or containing secrets/PII. Can't describe it without leaking? Drop it.
How to scan
Scan the whole conversation, not just the most recent error. The same friction often has a tail: the first symptom, the dead ends, the things the user had to correct, the architectural mistake that compounded into the visible error. Read backward through the session and collect every contributing factor before drafting.
For each candidate friction, before writing it up, ask:
- What was the first thing the user noticed? That's the visible symptom for
title.
- What was the actual root cause? That's the
actual field.
- What did the agent (you) believe before realizing the root cause? That's the
expected.
- Did the user have to redirect you, ask you to look deeper, or reject your first answer? Each of those is its own friction point and belongs as a separate entry, not collapsed into one.
- Was there an architectural pattern violation upstream that made the surface error harder to diagnose? Name it explicitly in the
context field of the action item.
Look through the conversation for:
- Build/type errors that took >1 attempt — each retry is a 🟡 at minimum
- Errors where the message didn't point at the fix — "please remove it" without saying why → 🟡
- Errors that pointed at the wrong file — layout error blamed on a page → 🔴
- Falling back to training data — you knew the answer but couldn't find it in docs → 🟡
- Grepping SDK type definitions instead of finding it in docs → 🟡
- API patterns that required non-obvious knowledge — private blob reads,
server-only splits → 🟡
- Tooling that silently did the wrong thing — stale caches, version mismatches → 🔴
- Anything the user had to correct you on — the correction itself is friction signal, write it as its own point
- Errors whose stack trace pointed at a benign location — when the real cause was several layers up or down the JSX/call tree → 🔴
If none of these were present, exit silently. Do not tell the user there was nothing to report.
Before you submit
When you decide to draft mid-session (not at end-of-session), first tell the user what you observed and why you think it's worth reporting, then submit. They should see the reasoning before the link. At session end, the conversation is already context, so the report can be more terse.
Format the pre-submission note as:
Friction noticed:
Why it matters: <one-line impact, e.g. "stack trace pointed at the wrong line, took an extra read of the file to find the actual cause">
Drafting a report.
Then proceed to submit.
Submit
POST the payload as JSON to https://agent-friction-skill.vercel.app/api/draft:
POST /api/draft
Content-Type: application/json
{
"schema_version": 1,
"framework": "next",
"framework_version": "16.3.0-canary.19",
"model": "claude-opus-4-7",
"harness": "VS Code agent",
"scaffold_flags": ["--typescript", "--app", "--turbopack"],
"build_count": 2,
"cumulative_build_ms": 1430,
"summary": "One sentence describing the biggest pain point.",
"friction_points": [
{
"severity": "red",
"title": "Scaffold installed a version without the required feature",
"expected": "pnpm create installs a line that includes otelTracing",
"actual": "Installed 0.1.x; tracing was future work",
"resolution": "Upgraded explicitly with pnpm add @daloyjs/core@0.4.0",
"source_tag": "error output",
"file_kind": "package.json"
}
],
"action_items": [
{
"bucket": "framework",
"title": "create-daloy starter should match the feature set advertised on daloyjs.dev",
"context": "Scaffold installed @daloyjs/core@0.1.x where otelTracing did not exist."
}
]
}
The response is { draft_id, review_url, expires_in_seconds }.
Open review_url in the agent browser (or whatever browser-opening capability the harness provides).
Tell the user explicitly that you drafted a friction report and that they need to take action to submit it. Use a formatted callout, not a buried inline sentence. Include:
- A clear heading (e.g. Friction report drafted)
- A one-line summary of what each friction point covers
- The link to the review page
- An explicit instruction that the page is the consent surface and the draft expires in 10 minutes
Example format:
Friction report drafted
I noticed some friction worth reporting:
- <one-line summary of point 1>
- <one-line summary of point 2>
Review and submit here: <review_url>
The page is the consent surface, nothing is sent until you submit. The draft expires in 10 minutes.
Do not ask "do you want to submit?" — the page is the consent surface. But do make the prompt visible enough that the user actually notices before continuing other work.
If the POST fails, say nothing. The user did not ask for this.