Metadata-Version: 2.4
Name: chartcoach
Version: 0.1.2
Summary: Python package and CLI for the ChartCoach visualization guideline catalog.
Keywords: data-visualization,guidelines,retrieval,visualization
Author: Péter Ferenc Gyarmati
Author-email: Péter Ferenc Gyarmati <dev.petergy@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Dist: bibtexparser>=1.1
Requires-Dist: click>=8
Requires-Dist: duckdb>=1.1
Requires-Dist: mdformat>=1
Requires-Dist: platformdirs>=4
Requires-Dist: polars>=1
Requires-Dist: pyarrow>=18
Requires-Dist: pyyaml>=6
Requires-Dist: tabulate>=0.10.0
Requires-Dist: lancedb>=0.33 ; extra == 'index'
Requires-Dist: mcp[cli]>=1.9 ; extra == 'mcp'
Requires-Python: >=3.11, <3.15
Project-URL: Repository, https://github.com/chartcoach/chartcoach
Project-URL: Issues, https://github.com/chartcoach/chartcoach/issues
Provides-Extra: index
Provides-Extra: mcp
Description-Content-Type: text/markdown

# chartcoach

Python package and CLI for the ChartCoach Guideline Catalog.

Read the package docs at [docs.chartcoach.dev/docs/packages/python](https://docs.chartcoach.dev/docs/packages/python).

For agent use, install the ChartCoach skill once, then ask the current agent to use it:

```bash
npx skills add chartcoach/skills --skill chartcoach
codex 'Use $chartcoach to access visualization design guidelines. Start by giving me a thematic overview of the catalog.'
```

The skill points agents to version-matched CLI-served skills. The CLI exposes catalog primitives, and task guidance lives in `chartcoach skills get <name>`.

The base package loads manifest-described catalog bundles, parses guidelines, and exposes typed records, Polars dataframe views, and native DuckDB SQL connections.

For application imports, add the package from the application root:

```bash
uv add chartcoach
uv add 'chartcoach[index]'
uv add 'chartcoach[mcp,index]'
```

```python
from chartcoach import Catalog

catalog = Catalog.open()
catalog.guidelines().select("id", "title")

conn = catalog.duckdb()
conn.sql("select id, title from guidelines limit 5").pl()
conn.close()
```

Install `chartcoach[index]` when code needs a LanceDB table over catalog documents:

```python
from chartcoach.search import index, search

table = index(catalog, "scratch/chartcoach-index")

docs = (
    table.search("overplotted scatter plots", query_type="fts", fts_columns="text")
    .where("role = 'overview'")
    .limit(3)
    .to_list()
)

hits = search(catalog, table, "overplotted scatter plots").to_dict()["rows"]
```

`index(catalog, uri)` writes a LanceDB table over catalog documents at the path you provide and returns the native LanceDB `Table`. Without an embedding function it creates a full-text table over the `text` column. Pass any LanceDB embedding function instance when you want LanceDB to fill the `vector` column from `text`:

```python
from chartcoach.search import index

table = index(
    catalog,
    "scratch/chartcoach-index",
    embedding=embedding_function,
)
```

Use `open("scratch/chartcoach-index")` for an existing table. Use `chartcoach.search.lance.documents(catalog)` when your code already owns a LanceDB connection and wants to call `db.create_table(...)` directly. Caller-owned tables should expose the catalog document columns `id`, `parent_id`, `role`, `labels`, `content_hash`, and `text`.

`model(embedding_function)` returns the LanceDB model used by `index(..., embedding=...)`. It defines `id`, `parent_id`, `role`, `labels`, `content_hash`, `text`, and `vector`, with `text` bound to `embedding_function.SourceField()` and `vector` bound to `embedding_function.VectorField()`.

Use DuckDB directly when notebooks, scripts, or agents need SQL joins over the derived catalog tables:

```python
from chartcoach.duckdb import connect_catalog

conn = connect_catalog(catalog)
conn.sql("""
select g.id, g.title, s.content, gs.source_title
from guidelines g
join sections s on s.guideline_id = g.id
left join guideline_sources gs on gs.guideline_id = g.id
where list_contains(g.labels, 'chart:scatter:avoid')
limit 5
""").pl()
conn.close()
```

Write a DuckDB database file when another tool needs durable SQL tables:

```python
duckdb_path = "scratch/catalog.duckdb"
catalog.write_duckdb(duckdb_path, overwrite=True)
```

The LanceDB index root can also be attached through DuckDB's Lance extension:

```sql
INSTALL lance;
LOAD lance;
ATTACH 'scratch/chartcoach-index' AS cc_index (TYPE LANCE);

select id, parent_id, role
from cc_index.main.catalog_documents
limit 5;
```

Run one-off CLI commands with `uvx chartcoach --help`.

These commands read the package-pinned default catalog artifact, inspect table schemas, write DuckDB tables, read guideline sections, and query indexed guideline rows.

```bash
uvx chartcoach catalog manifest --format markdown
uvx chartcoach catalog schema --tables --row-counts --format jsonl
uvx chartcoach catalog schema guidelines --format jsonl
uvx chartcoach catalog values labels \
  --contains chart: --format jsonl
uvx chartcoach catalog sql \
  "select id, title from guidelines where list_contains(labels, 'chart:bar')" \
  --format jsonl
DUCKDB_PATH=scratch/catalog.duckdb
uvx chartcoach catalog export duckdb \
  --out "$DUCKDB_PATH"
duckdb "$DUCKDB_PATH" \
  -c "select id, title from guidelines where list_contains(labels, 'chart:bar')"
uvx chartcoach catalog query \
  --label chart:bar --format jsonl
uvx chartcoach catalog read <guideline-id> \
  --section <role-from-manifest> --source-detail minimal --format jsonl
uvx chartcoach catalog cite <guideline-id> \
  --format markdown
INDEX_PATH=scratch/chartcoach-index
uvx --from 'chartcoach[index]' chartcoach catalog index create --index "$INDEX_PATH"
uvx --from 'chartcoach[index]' chartcoach catalog find \
  --index "$INDEX_PATH" \
  --where "role = 'overview'" \
  "overplotted scatter plot with too many points" --format jsonl
```

Every row-oriented command supports `--format jsonl`, so shell tools can handle projection and token control. Human `table` output uses rounded, wrapped columns for terminal scanning. JSON, JSONL, and CSV keep machine-readable stdout.

```bash
uvx chartcoach catalog schema --format jsonl |
  jq 'select(.table == "sections")'
```

The default catalog comes from package-pinned release metadata under `https://artifacts.chartcoach.dev/catalog/releases/<version>/<digest>/metadata.json` and is cached under the user's platform cache directory. The local cache mirrors the release layout at `catalog/releases/<version>/<digest>/`. Normal catalog reads download `MANIFEST.md` and `entries.parquet`. Heavier derived artifacts such as LanceDB indexes stay described in metadata until a caller asks for them. First-download notices go to stderr, so JSON, JSONL, and CSV stdout stay parseable. `catalog export duckdb` creates a DuckDB database file with the derived catalog tables. Use `catalog schema`, `catalog values`, and `catalog roles` before writing SQL against an unfamiliar catalog. `catalog read` returns deterministic catalog records. `catalog find` deduplicates indexed document matches to guideline-level typed rows.

Run catalog-only MCP tools with `chartcoach[mcp]`. Include `index` when agents
will call search tools.

```bash
uvx --from 'chartcoach[mcp]' chartcoach mcp serve
uvx --from 'chartcoach[mcp,index]' chartcoach mcp serve \
  --index scratch/chartcoach-index
```

Without an index, the MCP server exposes only `sql`. Pass `--index` to also register `search` against an existing LanceDB table.

Run package tests from the repository root:

```bash
uv run --package chartcoach --all-extras pytest packages/catalog-python/tests
```

## License

MIT. See [LICENSE](LICENSE).
