Data model and renderer for agent workspace screens.
Project description
agent-dashboard
Structured workspace screens for LLM agents — a data model and renderer that turns agent state into a deterministic, token-bounded plain-text prompt block.
Install
pip install agent-dashboard
Requires Python 3.14+.
Quickstart
from agent_dashboard import (
DashboardScreen,
DashboardHighlight,
DashboardActionRef,
ActionSpec,
render_screen,
)
# Define a reusable action once — bind it to a target per screen.
REPLY = ActionSpec(
action_id="reply",
label="Reply",
kind="action",
description="Send a reply to the message.",
requires_approval=True,
)
screen = DashboardScreen(
dashboard_id="inbox",
screen_id="turn-1",
breadcrumb=("Inbox",),
item_count=3,
body_lines=(),
screen_instructions="Reply to the oldest unread message first.",
highlights=(
DashboardHighlight(
highlight_id="msg-1",
title="Unread messages",
summary="3 unread messages waiting.",
severity="high",
suggested_next_step="Open the oldest unread message.",
),
),
screen_actions=(
REPLY.for_target(
source_id="inbox",
item_id="msg-1",
display_name="Re: Project update",
),
),
)
rendered = render_screen(screen, token_budget=512)
# Pass `rendered` directly into your LLM prompt.
render_screen() produces deterministic plain text — same input, same output:
Attention items: 3
Breadcrumb: Inbox
View state: collapsed
Reply to the oldest unread message first.
Highlights:
- [high/active] Unread messages — 3 unread messages waiting.
next: Open the oldest unread message.
Screen actions:
- reply: Reply [target=inbox/msg-1:Re: Project update] [requires approval] — Send a reply to the message.
The token_budget parameter is an approximate token ceiling (4× char multiplier).
Output that exceeds the budget is truncated with ... [truncated].
Core API
All names below are importable directly from agent_dashboard.
| Name | What it is |
|---|---|
DashboardScreen |
Immutable snapshot of what an agent sees — breadcrumb, highlights, actions, body lines, instructions |
DashboardHighlight |
A notable item: id, title, summary, severity, optional next step |
DashboardActionRef |
A single available action with optional target binding and approval flag |
ActionSpec |
Reusable action definition; .for_target() produces a bound DashboardActionRef |
render_screen(screen, *, token_budget) |
Pure function → token-bounded plain-text string |
screen_to_dict(screen) |
Serialize to a plain dict (tuple fields → lists) |
screen_from_dict(data) |
Deserialize from dict; ignores unknown fields |
SeverityLevel, StatusValue, ViewState |
Literal type aliases for IDE/type-checker feedback; Python does not enforce them at runtime |
Two action lists
DashboardScreen has two action fields:
screen_actions— rendered into the plain-text prompt byrender_screen()underScreen actions:. The agent reads these and names one in its structured response.tool_calls— not rendered into the prompt. Pass these out-of-band to your model API as native function/tool definitions (e.g.tools=in the Anthropic or OpenAI SDK). Both fields holdDashboardActionRef; the split is about which rendering channel carries the action, not about severity or approval.
view_state
view_state defaults to "collapsed" and appears in the rendered output as View state: collapsed. The value "expanded" is reserved — you can set it explicitly on a screen, and the renderer will emit View state: expanded, but the library does not currently change rendering behaviour based on this field. Future renderer versions may use it to control whether body lines are shown.
ScreenHub — async reactive streaming
ScreenHub lets you publish screens from any thread and subscribe to them
as an async stream. Useful when an agent loop runs in a worker thread and
needs to push state to an async consumer (TUI, WebSocket handler, test fixture).
from agent_dashboard.hub import ScreenHub
async with ScreenHub() as hub:
# publish from any thread:
hub.publish(screen, group_id="turn-1")
# subscribe as an async stream:
async for screen, group_id in hub.subscribe():
...
# late subscriber? get the last snapshot immediately:
async for screen, group_id in hub.subscribe_from_latest():
...
ScreenHub is not re-exported from agent_dashboard — import it explicitly
to keep the base import free of asyncio.
Additional modules
| Module | What it provides | Import |
|---|---|---|
agent_dashboard.testing |
make_screen(), screen_diff(), assertion helpers, hub_context() — test helpers with no pytest coupling |
explicit |
agent_dashboard.tui |
live_tui(hub), live_tui_context(hub) — read-only live terminal display via rich |
pip install agent-dashboard[tui] |
Testing example
from agent_dashboard.testing import (
assert_body_contains,
assert_highlight_ids,
assert_render_fits_budget,
make_screen,
screen_diff,
hub_context,
)
# Minimal valid screen with sensible defaults — override any field:
screen = make_screen(dashboard_id="inbox", item_count=5)
# Structural diff between two screens:
summary = screen_diff(old_screen, new_screen)
assert summary.item_count_delta == 2
# Author-facing assertions with useful failure messages:
assert_highlight_ids(screen, ("overdue-invoice", "missing-owner"))
assert_body_contains(screen, "Store #1610", "Phase: inspection")
rendered = assert_render_fits_budget(screen, token_budget=512)
# Hub fixture for async tests (works with pytest-asyncio asyncio_mode="auto"):
async with hub_context(initial_screens=[(screen, "turn-1")]) as hub:
async for s, group_id in hub.subscribe_from_latest():
...
Authoring patterns
Keep text and structured data separate. title, summary, and body_lines
are what the agent reads; avoid parsing those fields later to recover IDs,
colors, indexes, or routing hints. Put stable machine-readable data in ids or
metadata:
DashboardHighlight(
highlight_id="figure-3",
title="Figure 3",
summary="triangle · red",
severity="high",
metadata={"shape": "triangle", "color": "red", "position": 3},
)
If a consumer-specific UI needs more state than DashboardScreen carries,
keep that adapter in the consuming application. agent-dashboard intentionally
models the shared projection boundary; richer HTML, persistence, transport,
and tool execution stay outside the library.
Design
The library is transport-agnostic and stateless. It does not execute actions, manage session state, or call any model API. Those concerns belong in the consuming application.
Full design documentation — boundary decisions, proposals, and glossary — lives
in design/.
Release history lives in CHANGELOG.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_dashboard-1.0.0.tar.gz.
File metadata
- Download URL: agent_dashboard-1.0.0.tar.gz
- Upload date:
- Size: 100.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c21a421468fc3e40da3e7b30623a034361334d6bf9c811274a6361f133254be9
|
|
| MD5 |
69494d7dbdabf7bdc2fb03e8563d228c
|
|
| BLAKE2b-256 |
35fb2d3af31767143d8c34e72ab2463a395f9ff9d609c6248a9b6daa89cf9153
|
Provenance
The following attestation bundles were made for agent_dashboard-1.0.0.tar.gz:
Publisher:
workflow.yml on uthunderbird/agent-dashboard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_dashboard-1.0.0.tar.gz -
Subject digest:
c21a421468fc3e40da3e7b30623a034361334d6bf9c811274a6361f133254be9 - Sigstore transparency entry: 1591697487
- Sigstore integration time:
-
Permalink:
uthunderbird/agent-dashboard@e5b0057ad257b7b897337c17cee5bc5873bc6e00 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/uthunderbird
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@e5b0057ad257b7b897337c17cee5bc5873bc6e00 -
Trigger Event:
push
-
Statement type:
File details
Details for the file agent_dashboard-1.0.0-py3-none-any.whl.
File metadata
- Download URL: agent_dashboard-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7a0c46de46f67e21be198054c0b25671155829245c00e48b79a401167b5b499
|
|
| MD5 |
f248d126662e6e5a663ef22101e4ce56
|
|
| BLAKE2b-256 |
3184ae18f341f77c722aedae1cecd0d847b037b61b442e179022dbfbf7326e6a
|
Provenance
The following attestation bundles were made for agent_dashboard-1.0.0-py3-none-any.whl:
Publisher:
workflow.yml on uthunderbird/agent-dashboard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_dashboard-1.0.0-py3-none-any.whl -
Subject digest:
e7a0c46de46f67e21be198054c0b25671155829245c00e48b79a401167b5b499 - Sigstore transparency entry: 1591697906
- Sigstore integration time:
-
Permalink:
uthunderbird/agent-dashboard@e5b0057ad257b7b897337c17cee5bc5873bc6e00 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/uthunderbird
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@e5b0057ad257b7b897337c17cee5bc5873bc6e00 -
Trigger Event:
push
-
Statement type: