Skip to content

Commit d830cff

Browse files
committed
docs(readme): rebalance toward usage — collapse JSONL wall, concrete before/after
Feedback: too much 'why cool', not enough 'how to use'. Changes: (1) dropped the 'Built for the agent era' paragraph — redundant with 'Who it's for' above. (2) Rewrote usage sections with concrete before/after — Claude Code section now shows a real agent turn + the exact JSON returned. (3) Added a shell-script usage example with jq parsing. (4) Renamed 'Agent-native example' to a collapsible <details> block under the patterns table so the wall of JSONL is available but not in the scroll path. (5) Renamed 'Use cases' → 'Common patterns' — grounds the reader in what works, not abstract positioning.
1 parent 59aeac7 commit d830cff

1 file changed

Lines changed: 61 additions & 50 deletions

File tree

README.md

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -67,84 +67,75 @@ macOS-only is a choice, not a gap. A Linux port (GTK + WebKit2) and a Windows po
6767

6868
---
6969

70-
## Built for the agent era
70+
## Use it
7171

72-
The Opus 4.7 / Claude Code / MCP generation of tools is reasoning well enough that human-in-the-loop moments are common and consequential. Deploy approvals. Reviewer picks. Config forms. Diff acknowledgements. These deserve a real UI — not `[y/N]`.
72+
### With Claude Code
7373

74-
`webview-cli` is how you give your agents that UI without bundling a browser.
74+
Install the bundled skill once:
7575

76-
### With Claude Code (via the bundled skill)
76+
```bash
77+
ln -s "$(pwd)/skill" ~/.claude/skills/webview # or use the installer flag
78+
```
79+
80+
Then ask your agent anything that needs structured input from you. The skill handles the rest — generates A2UI, spawns the binary, parses the result, returns typed data. You never write JSONL by hand.
81+
82+
**Example: deploy approval.** Agent says:
83+
84+
> "I'm about to deploy `billing-webhook` to production. Should I proceed?"
85+
86+
The skill opens a native window with the change summary, a rollout radio (canary / full), a comment field, and Approve/Cancel. You click. The agent receives:
7787

78-
The installer drops a `/webview` skill into `~/.claude/skills/webview/`. Your agent just does:
88+
```json
89+
{"action": "approve", "data": {"rollout": "canary", "note": "Monitoring on standby"}}
90+
```
7991

80-
> "I need approval before deploying. Show the user the change summary with an option to add a comment."
92+
and continues. No terminal input. No context loss.
8193

82-
Claude Code routes through the skill, generates A2UI JSONL, invokes `webview-cli --a2ui`, parses the returned JSON, and continues with the result. You never touch JSONL by hand.
94+
Other patterns the skill handles out of the box: single-select from agent-found options (PRs to review, branches to rebase), multi-field config forms, diff-and-acknowledge flows. Full skill docs: [`skill/SKILL.md`](skill/SKILL.md).
8395

84-
### With OpenAI's Codex CLI or Gemini CLI
96+
### With OpenAI Codex CLI, Gemini CLI, or any subprocess-capable agent
8597

86-
Both are subprocess-capable. Any agent that can `spawn_subprocess` and read stdout can use webview-cli. Minimal wrapper in Python works for either:
98+
The binary is protocol-agnostic. Anything that can `spawn_subprocess` and read stdout works:
8799

88100
```python
89101
import subprocess, json
90102

91103
result = subprocess.run(
92104
["webview-cli", "--a2ui", "--timeout", "120"],
93-
input=my_a2ui_jsonl,
105+
input=your_a2ui_jsonl,
94106
capture_output=True, text=True
95107
)
96-
if result.returncode == 0:
97-
response = json.loads(result.stdout)
98-
# response['data']['action'] = button clicked
99-
# response['data']['data'] = form field values
108+
# result.returncode: 0=submitted, 1=cancelled, 2=timeout, 3=error
109+
# json.loads(result.stdout) has {"status", "data": {"action", "data": {...}}}
100110
```
101111

102-
Protocol details in [`docs/protocol.md`](docs/protocol.md). A sharable Codex/Gemini tool definition is in [`examples/openai-codex-tool.md`](examples/openai-codex-tool.md).
103-
104-
### With shell scripts or MCP servers
105-
106-
`webview-cli` is a Unix tool. Stdin JSON in, stdout JSON out. Pipes work. Blocking semantics work. Exit codes work. Use it anywhere a subprocess can run.
107-
108-
---
112+
A complete wrapper plus a Codex tool definition you can paste into your agent config: [`examples/openai-codex-tool.md`](examples/openai-codex-tool.md).
109113

110-
## Agent-native example
111-
112-
Here's what an agent approval flow looks like end-to-end. Your agent pipes this on stdin to `webview-cli --a2ui`:
113-
114-
```json
115-
{"surfaceUpdate":{"components":[{"id":"root","component":{"Column":{"children":{"explicitList":["card"]}}}}]}}
116-
{"surfaceUpdate":{"components":[{"id":"card","component":{"Card":{"children":{"explicitList":["title","diff","risk","note","btns"]}}}}]}}
117-
{"surfaceUpdate":{"components":[{"id":"title","component":{"Text":{"usageHint":"h2","text":{"literalString":"Deploy billing-webhook to prod?"}}}}]}}
118-
{"surfaceUpdate":{"components":[{"id":"diff","component":{"Text":{"usageHint":"body","text":{"literalString":"3 files · +47/-12 · CI green · MASS-683"}}}}]}}
119-
{"surfaceUpdate":{"components":[{"id":"risk","component":{"RadioGroup":{"label":{"literalString":"Rollout"},"fieldName":"rollout","options":[{"value":"canary","label":"Canary (10%)"},{"value":"full","label":"Full rollout"}]}}}]}}
120-
{"surfaceUpdate":{"components":[{"id":"note","component":{"TextInput":{"label":{"literalString":"Deploy note"},"fieldName":"note","multiline":true}}}]}}
121-
{"surfaceUpdate":{"components":[{"id":"btns","component":{"Row":{"alignment":"end","children":{"explicitList":["c","go"]}}}}]}}
122-
{"surfaceUpdate":{"components":[{"id":"c","component":{"Button":{"label":{"literalString":"Cancel"},"variant":"secondary","action":{"name":"cancel"}}}}]}}
123-
{"surfaceUpdate":{"components":[{"id":"go","component":{"Button":{"label":{"literalString":"Deploy"},"variant":"success","action":{"name":"approve"}}}}]}}
124-
{"beginRendering":{"root":"root"}}
125-
```
114+
### From a shell script or MCP server
126115

127-
Native window opens. User picks "Canary (10%)", types a note, clicks Deploy. Stdout gets:
116+
It's a Unix tool. Stdin in, stdout out, exit codes report outcome. Pipes work. Blocking works. Put it wherever a subprocess can run:
128117

129-
```json
130-
{"status":"completed","data":{"action":"approve","data":{"rollout":"canary","note":"Monitoring dashboard on standby"},"context":{}}}
118+
```bash
119+
# Approval gate in a CI/deploy script
120+
RESULT=$(cat my-form.jsonl | webview-cli --a2ui --title "Deploy?" --timeout 300)
121+
case $? in
122+
0) ACTION=$(echo "$RESULT" | jq -r '.data.action'); [ "$ACTION" = "approve" ] && deploy ;;
123+
1) echo "User cancelled." ;;
124+
2) echo "Timed out — no response in 5 min." ;;
125+
esac
131126
```
132127

133-
Exit code `0`. The agent continues. If the user cancelled → exit `1`. If timeout → exit `2`. If the URL/load errored → exit `3`.
134-
135-
**The point: your agent doesn't write HTML/CSS. It emits a flat JSONL description of what UI it wants, and a native window appears.**
136-
137128
---
138129

139-
## Use cases
130+
## Common patterns
140131

141132
<table>
142133
<tr>
143134
<td width="50%" valign="top">
144135

145136
### Deploy approval
146137

147-
Show the diff, context, and a comment field. One click, agent continues with a structured result and the note goes into the deploy log.
138+
Show the diff, context, a comment field. One click, agent continues with structured result plus the note going into the deploy log.
148139

149140
[`examples/hero-deploy-approval.jsonl`](examples/hero-deploy-approval.jsonl)
150141

@@ -153,9 +144,9 @@ Show the diff, context, and a comment field. One click, agent continues with a s
153144

154145
### Pick from options
155146

156-
Agent enumerates candidates (PRs, branches, customers, files). User picks one with radio buttons. Agent proceeds.
147+
Agent enumerates candidates (PRs, branches, files). User picks one with radio buttons. Agent proceeds with the choice.
157148

158-
[`examples/multi-field-form.jsonl`](examples/)
149+
[`examples/`](examples/)
159150

160151
</td>
161152
</tr>
@@ -164,21 +155,41 @@ Agent enumerates candidates (PRs, branches, customers, files). User picks one wi
164155

165156
### Multi-field config
166157

167-
Text inputs + selects + checkboxes in one native form. Better than 6 terminal prompts in a row.
158+
Text inputs + selects + checkboxes in one native form. Better than six `read -p` prompts in a row.
168159

169160
</td>
170161
<td width="50%" valign="top">
171162

172163
### Custom HTML via `agent://`
173164

174-
When A2UI's components aren't enough (charts, diffs, diagrams), pipe base64-encoded HTML on stdin. In-memory scheme handler serves it no HTTP server.
165+
When the A2UI catalog isn't enough charts, diffs, diagramspipe base64-encoded HTML on stdin. In-memory scheme handler serves it, no HTTP server.
175166

176167
[`docs/protocol.md#agent-scheme`](docs/protocol.md)
177168

178169
</td>
179170
</tr>
180171
</table>
181172

173+
<details>
174+
<summary><b>What the raw A2UI JSONL looks like</b> (click to expand — the skill writes this for you)</summary>
175+
176+
```json
177+
{"surfaceUpdate":{"components":[{"id":"root","component":{"Column":{"children":{"explicitList":["card"]}}}}]}}
178+
{"surfaceUpdate":{"components":[{"id":"card","component":{"Card":{"children":{"explicitList":["title","diff","risk","note","btns"]}}}}]}}
179+
{"surfaceUpdate":{"components":[{"id":"title","component":{"Text":{"usageHint":"h2","text":{"literalString":"Deploy billing-webhook to prod?"}}}}]}}
180+
{"surfaceUpdate":{"components":[{"id":"diff","component":{"Text":{"usageHint":"body","text":{"literalString":"3 files · +47/-12 · CI green · MASS-683"}}}}]}}
181+
{"surfaceUpdate":{"components":[{"id":"risk","component":{"RadioGroup":{"label":{"literalString":"Rollout"},"fieldName":"rollout","options":[{"value":"canary","label":"Canary (10%)"},{"value":"full","label":"Full rollout"}]}}}]}}
182+
{"surfaceUpdate":{"components":[{"id":"note","component":{"TextInput":{"label":{"literalString":"Deploy note"},"fieldName":"note","multiline":true}}}]}}
183+
{"surfaceUpdate":{"components":[{"id":"btns","component":{"Row":{"alignment":"end","children":{"explicitList":["c","go"]}}}}]}}
184+
{"surfaceUpdate":{"components":[{"id":"c","component":{"Button":{"label":{"literalString":"Cancel"},"variant":"secondary","action":{"name":"cancel"}}}}]}}
185+
{"surfaceUpdate":{"components":[{"id":"go","component":{"Button":{"label":{"literalString":"Deploy"},"variant":"success","action":{"name":"approve"}}}}]}}
186+
{"beginRendering":{"root":"root"}}
187+
```
188+
189+
That's the whole approval UI above. One line per component, flat adjacency list, LLM-friendly to generate. The skill produces this from a short natural-language description of the UI.
190+
191+
</details>
192+
182193
---
183194

184195
## Install

0 commit comments

Comments
 (0)