tart — live terminal artifacts
A live terminal artifact is a dashboard that stays open, keeps its own data fresh — or says plainly that it hasn't — and can be found and read again later, by you or by an agent. Local, and authorable in a few lines.
uv tool install tartifacts # the command is `tart`
Installed as tartifacts because PyPI's tart is an unrelated
radio-telescope library, which owns the tart import name too. The command
you type, and the .tart/ directory, are unaffected.
Why not just let each agent hand-roll a TUI?
Mostly, you should. rich already draws tables, panels and sparklines
well, and tart doesn't replace it — you still write rich code, and
render() may return any rich renderable. tart is not a rendering
framework.
What repeats isn't the drawing. It's everything wrapped around it:
- raw-mode terminal setup, and teardown that survives a dead tty
- an event loop and key dispatch, with
q/rhandled for you - watching a data file and redrawing when it changes
- knowing when data went stale, and re-running the thing that produces it
- finding the dashboard again from any directory, on any machine
- rendering one frame headless — an agent can't see a TUI it just
wrote; without
--once/--jsonit would have to drive a multiplexer and screen-scrape its own output
Each is a day of small annoyances, and every hand-rolled TUI rewrites them slightly differently.
The sharper argument is that the bugs repeat too. Two artifacts here
independently grew a byte-identical sparkline() — with the same defect,
because rich crops at the right edge, so a 30-day series in a narrow
panel silently hid today. And every artifact under-reserved its height by
exactly 4 rows (a table's border and header), losing its help line off the
bottom. Both only appear at a particular terminal width. A green test
suite and a quick eyeball won't catch either. Fixed once here, they're
fixed everywhere.
When you don't need this: a script that prints a table and exits. That is the whole distinction — live is the word doing the work. Reach for tart when something should stay open, stay fresh, and be findable later.
How much does it actually take over? Across the five artifacts built on it, 14–23 lines out of 178–273 touch tart at all. The rest is yours.
An artifact is three pieces
.tart/thing.json manifest — name, what produces the data, when it goes stale
fetch script writes JSON to tartifacts.data_path()
render script render(state, console) -> any rich renderable
The manifest is the only place a path is written down, so neither script repeats it:
{
"title": "Bedrock spend",
"run": "uv run --with rich --with tartifacts python bin/dash.py",
"data": "bin/data/bedrock_usage.json",
"fetch": "uv run --with tartifacts python bin/snapshot.py",
"stale_after": "4h",
"auto_refresh": true
}
Only title and run are required. The rest declare provenance, which
is what lets tart run refresh stale data on its own, diagnose a dead dashboard, and another agent on another machine repair it from the manifest alone. With auto_refresh`, an external cron is optional
rather than load-bearing.
The render script
from tartifacts import app, widgets
def render(state, console):
return widgets.stack(
widgets.header(f"{len(state['data']['rows'])} rows"),
widgets.trend(state["data"]["daily"], style="green"),
)
app.run(render=render, state={"cursor": widgets.Cursor()})
Only render is required — the title and the data source come from the
manifest. You get --once/--json, refresh, and discovery for free.
CLI
tart list # what's declared, and what's live right now
tart run <name> # launch it (fetches first if data is stale)
tart render <name> # one frame, headless — no terminal needed
tart render <name> --json # its numbers as JSON, for agents and pipelines
tart fetch <name> # re-run its data-producing command
tart roots add <path> # a workspace to scan for artifacts
tart reindex # re-find manifests too deep for the normal scan
tart --skill # the full reference, written for an agent
TART_HOME relocates tart's own state (default ~/.tart).
Quick start
uv tool install tartifacts
tart roots add ~/dev/quarkle # scan a workspace, once
Full reference
tart --skill prints everything: the manifest schema, the app.run
contract, the widget set, responsive-layout rules, and the gotchas. It's
written to be read by an agent before it builds or debugs an artifact, and
it's kept honest by tests that fail when a CLI subcommand, manifest field,
app.run parameter, widget, or environment variable exists but isn't
documented.
Development
make check # lint + tests
make install # (re)install the CLI from this checkout
When working on tart itself, point artifacts at your checkout with
--with-editable /path/to/tart, never --with — uv run --with <path>
builds and caches a wheel, so your edits silently don't apply.
A running artifact won't pick up tart changes. Python imports at startup, so quit and relaunch after upgrading. The failure is silent — a keypress appears to do nothing rather than erroring.
Metadata
Release files for tartifacts 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tartifacts-0.1.0.tar.gz | 83.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tartifacts-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 136.6 kB
Release files / tartifacts-0.1.0.tar.gz
| Download URL | tartifacts-0.1.0.tar.gz |
|---|---|
| Size | 83.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83597471727017a74dd76bc2048157f8b09fe4484b7490e1447aba81bef10d55
|
|
BLAKE2b-256 checksum How to use checksums |
82fee55cde5575887e769fe34e6ca18ee5e4409424efdc2754b3ef867ab27708
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.15
|
Release files / tartifacts-0.1.0-py3-none-any.whl
| Download URL | tartifacts-0.1.0-py3-none-any.whl |
|---|---|
| Size | 53.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
78e4b75bffe7c0d0776c6fa8fc0d58cd1190675d674bc6b33a9cae05e4d013a9
|
|
BLAKE2b-256 checksum How to use checksums |
201ba34a9074682ea1fecea968b8e7a28930efba0a60e1fd8e74084c21f12476
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.15
|