Generative widgets are lightweight, session-scoped UI panels backed by Markdown files. They let an agent show compact task state, decisions, and action links without turning that UI into model-facing transcript history.
Widgets are designed to be:
- Durable enough for UI state: they live on disk with the session and can be rehydrated after a client reconnects.
- Ephemeral enough for task UX: agents should update, consolidate, or delete widgets as the task changes.
- Renderer-owned: agents provide semantic Markdown; the TUI and web UI own layout, focus, scrolling, and hide/show controls.
Agents create widgets by writing UTF-8 Markdown files with a .md extension to
the current session's widget directory. Agents should not guess this path: call
agentd_context and use session_widgets.dir from the response.
widgets/
task-status.md
review.md
Each Markdown file becomes one widget. The filename is used as the stable widget
id, and the file stem becomes the title fallback (task-status.md renders as
task status). Updating the file updates the widget; deleting the file removes
it.
Optional frontmatter can configure widget metadata:
---
placement: inline
title: Confirm action
---
# Continue?
[OK](agentd:action/ok?close=1)placement: sticky is the default. placement: inline renders the widget as a
single-use full-width dialog at the bottom of the session. Only one inline
widget is shown at a time, it auto-focuses, blocks normal terminal/prompt focus,
and closing it deletes the backing Markdown file so it will not reappear after a
client or daemon restart.
Widgets are UI state, not transcript history. Clients can restore current widgets after reconnect without replaying the model conversation.
Widgets use "construct Markdown": normal Markdown plus a small set of semantic extensions. Renderers parse the pieces they understand and degrade the rest to plain text.
Common Markdown works well:
# Build status
- [x] Compile
- [~] Run checks
- [ ] Merge PR
[Open PR](agentd:action/open-pr)agentd_context advertises supported widget_markdown_extensions. The current
special extension is timeline, which renders top-level bullets/checklists as a
vertical timeline with nested detail lines.
:::timeline
- [x] Prepare branch
- [x] Create worktree
- [x] Commit change
- [~] Validate
- [x] cargo build
- [ ] CI
- [ ] Merge and clean up
:::Supported top-level markers:
| Marker | Meaning |
|---|---|
[x] |
Done |
[~] |
Active/current |
[ ] |
Todo |
[!] |
Blocked/warning |
| plain bullet | Milestone |
Nested bullets render under their parent at arbitrary depth.
Widgets can include action links with the agentd:action/ scheme:
[Run checks](agentd:action/run-checks)
[Open PR](agentd:action/open-pr?key=o)When a user activates an action, the owning session receives a normal observation such as:
OBSERVATION: ui.action {"panel_id":"task-status","action_id":"run-checks","label":"Run checks"}
Keyboard shortcuts are opt-in with ?key=<key>. They are only active while the
widget/card is focused. Add close=1 to dispatch the action and then close the
containing widget; for inline widgets this also deletes the backing Markdown
file. Action links are intent signals only; they do not bypass normal tool
approvals, safety policy, or user confirmation requirements.
A typical task status widget:
# PR cleanup
:::timeline
- [x] Wait for CI
- [x] Build & test passed
- [~] Merge PR
- [ ] Squash merge
- [ ] Cleanup
- [ ] Remove worktree
- [ ] Pull main
- [ ] cargo build
:::
[Open PR](agentd:action/open-pr?key=p)Write it to the current session's widget directory:
cat >"$CONSTRUCT_SESSION_WIDGETS_DIR/pr-cleanup.md" <<'EOF'
# PR cleanup
:::timeline
- [x] Wait for CI
- [~] Merge PR
- [ ] Cleanup
:::
[Open PR](agentd:action/open-pr?key=p)
EOF