Count the round trips your agent skill makes the user pay

Ghostwriter · No. 064

Shipped

Ghostwriter v0.13.0 through v0.14.1 shipped as one arc: cards that show a terminal must be transcribed from real output instead of invented, the session now opens with a single combined dialog instead of a chain of questions, drafts render with LinkedIn’s ~210-character fold marked, and startup checks went quiet after a real session showed them spamming the chat. The shared idea is treating a conversational agent skill like any other interface and budgeting its interaction cost. That is what this guide covers.

The cost model: every question is a round trip

Nielsen Norman Group defines interaction cost as the sum of mental and physical effort a user spends to reach their goal: reading, clicking, waiting, shifting attention. A chat-based agent has exactly one currency, the round trip. Each time the agent stops to ask something, the user must read, decide, answer, and wait for the next stop. Two design rules fall out of that:

  1. Deterministic work never costs a round trip. Config checks, file reads, and bookkeeping run silently; the user sees the first message only when there is something to decide.
  2. When the agent does stop, it batches every pending decision into that one stop, with enough context in the question that the user does not have to ask anything back.

The releases here are those two rules applied to a working skill, plus a third that turned out to matter as much: never make the user review something the agent invented when real data existed.

Merge the questions into one dialog

The skill’s old opening asked how the last post performed, then separately offered post ideas, one question per topic lane. In Claude Code, a skill asks via the AskUserQuestion tool, and the shape of that call is the whole UX. The pattern that works is a single flattened, ranked question:

Question: "What should today's post be about?"
Context shown above the question: the full idea board in chat
  (trending, radar, and recent-project lanes), plus how the
  last post actually performed.
Options (max 4):
  1. <strongest idea, one-line preview of the angle>
  2. <second idea, preview>
  3. <third idea, preview>
  4. "Show more ideas"

Two hard-won specifics. First, the tool caps options at four, so a menu that “asks for 5-6 options” simply loses the tail; rank and cut, and make the fourth option the escape hatch. Second, put a preview under each option, not just a label; a label forces the user to mentally expand it, which is interaction cost in the NN/g sense even when no click happens.

The same one-stop rule applies mid-flow. When the skill later asks which visual form the post should take, the same dialog also carries the output-provenance question (more below), so choosing a card never costs a second stop.

Keep the setup silent

The v0.14.0 release added the board and the merged dialog, and a real session immediately showed the other half of the cost: before the assistant said a single word, the chat filled with echoed section headers and bare pwd and ls calls from setup checks. None of it was for the user; all of it was in front of the user.

The fix in v0.14.1 was to collapse setup into one or two terse compound calls with no narration:

test -d "$SKILL_STATE" && cat "$SKILL_STATE/config.json" && ls "$SKILL_STATE/drafts" 2>/dev/null

The instruction that matters in the skill prose: setup and bookkeeping run as batched commands, and nothing is echoed for the user’s benefit; the first user-visible output of a session is the idea board. Anthropic’s own guidance on designing agent skills frames a skill as layered instructions the agent loads as needed; the layer the user actually experiences is the conversation, and it deserves the same deliberate design as the file layout.

Ground the artifact in real output

The expensive lesson. One card was a terminal panel showing my fitness agent’s output, and the agent composed the terminal contents from imagination instead of running the tool. Every line looked plausible; none was real. I spent about nine review rounds correcting invented details one at a time, and a one-character border misalignment still survived all nine.

v0.13.0 made real output the raw material instead of the correction target:

Real-output card contract
1. Capture first: run the CLI/MCP tool, or take the user's paste or
   screenshot, into images/<slug>.source.txt before authoring.
2. Author as condensation: select and trim lines from the capture;
   never compose new ones.
3. Unknown values render as dashes, never as plausible inventions.
4. Self-compare the render against the user's reference screenshot
   before showing it (the mirror check).

This is the artifact-generation version of what Anthropic documents for reducing hallucinations in text: ground the response in extracted quotes from the source material and allow an explicit “I don’t know” instead of a confident guess. A dash in a terminal card is the visual “I don’t know”, and it is always cheaper than a review round.

The release also added a mechanical check where prose had failed: a lint that measures terminal-row alignment in the rendered card. It caught the one-character border defect that nine rounds of human review had missed.

Verify your own skill’s cost

Two checks, both cheap. First, run your skill start to finish and count the stops: how many times did it wait on you before the first real deliverable? The target for this skill is one. Second, count what precedes the first assistant message; if raw command output appears in the chat before any prose, your setup is leaking. For generated artifacts, the check is one question: for every fact in the artifact, can you point at the captured source line it came from? If the answer needs the word “plausible”, you are about to pay review rounds for it.

Gotchas

Invented output costs you one review round per invented detail. The trap: letting the agent compose “example” output for something that really runs. The symptom: a long polite loop of “actually, the date format is different, and that flag doesn’t exist”; about nine rounds in my case. The escape: capture-first, author-as-condensation, dashes for unknowns. The capture also feeds real numbers into the post body, so the fix pays twice.

A UX improvement can ship with its own regressions. The trap: shipping a conversational redesign and assuming the transcript reads the way you imagined. v0.14.0 merged the dialogs, and the next real session revealed noisy setup output and an idea menu that paged one question per lane, forcing paging past unrelated cards after the pick was already made. The escape: read a real session transcript after every UX change, the way you would watch a usability test; both regressions were obvious in one reading and fixed in v0.14.1.

Know your question tool’s hard limits before designing the menu. The trap: designing an idea menu around five or six options when AskUserQuestion renders at most four. The symptom is silent truncation of the choices you ranked lowest, which the user never knows existed. The escape: design for the cap (top three plus “show more”), and put the full board in chat above the question so the four options are a ranking, not the whole universe.

Sources

Changelog

  • feat(ghostwriter): real-output card grounding + hero-terminal budget (v0.13.0) (#80) (157735b)
  • feat(ghostwriter): conversational UX pass — one-dialog start, four-section idea board, fold-marked drafts (v0.14.0) (#81) (2799def)
  • fix(ghostwriter): quiet startup checks + one-question idea picker (v0.14.1) (530b2e8)