Metadata-Version: 2.5
Name: tartifacts
Version: 0.1.0
Summary: Live terminal artifacts — dashboards that stay open, stay fresh, and stay findable
Project-URL: Homepage, https://github.com/tg1482/tart
Project-URL: Source, https://github.com/tg1482/tart
Project-URL: Issues, https://github.com/tg1482/tart/issues
Project-URL: Changelog, https://github.com/tg1482/tart/blob/master/CHANGELOG.md
Author-email: Tanmay Gupta <tg1482@stern.nyu.edu>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,cli,dashboard,rich,terminal,tui
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: Terminals
Requires-Python: >=3.10
Requires-Dist: rich>=13.0
Description-Content-Type: text/markdown

# 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.

```bash
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`/`r` handled 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`/`--json` it 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:

```json
{
  "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

```python
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

```bash
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

```bash
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

```bash
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.
