Metadata-Version: 2.5
Name: costcrunch
Version: 0.1.0
Summary: CostCrunch from Python, your terminal, and AI assistants (MCP).
Project-URL: Homepage, https://costcrunch.ai
Project-URL: Documentation, https://support.costcrunch.ai
Author-email: CostCrunch <support@costcrunch.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: cli,construction,costcrunch,invoices,mcp,procurement
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
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
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Requires-Dist: mcp<3,>=2.3
Requires-Dist: rich>=13
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# CostCrunch for Python, the terminal and AI assistants

One package, three ways in to your CostCrunch data:

| | |
|---|---|
| **CLI** | `cost documents list --status needs_attention` |
| **Python** | `CostCrunch().materials.history(material_id)` |
| **MCP** | Ask Claude, Cursor or any MCP client *"what did we pay for 5/8 sheetrock last month, and is that a good price?"* |

All three are generated from the same list of operations, so they always match. Everything is
read-only and scoped to your company: you see exactly what you see in the CostCrunch app.

## Install

```sh
uv tool install costcrunch          # or: pipx install costcrunch
cost auth login
```

This opens your browser to sign in with Google. For an email + password account, use
`cost auth login --email you@company.com`. Your session is stored in `~/.config/costcrunch/credentials.json`,
readable only by you. `cost auth logout` removes it.

Or use an **API key**: create one in CostCrunch under **Settings › Connections › API**, then
`cost auth login --api-key` (it asks for the key), or set `COSTCRUNCH_API_KEY`. A key belongs to
one company, can only read, and works until you revoke it on that page.

If you belong to more than one company: `cost account orgs`, then
`cost account use-org <id>` (or pass `--org <id>` to any command).

## CLI

```sh
cost search all "tri-state"                        # anything: documents, suppliers, materials...
cost documents list --type invoice --since 2026-10-01
cost documents get <document-id>                   # header + line items + price checks
cost suppliers list
cost suppliers materials <supplier-id> --search sheetrock
cost projects get <project-id>                     # spend by supplier, month, cost type
cost materials find "5/8 sheetrock"                # by meaning, not just words
cost materials history <material-id> --since 2026-01-01
cost materials prices <material-id>                # your history vs other suppliers vs online
cost spend monthly
```

Add `--json` to any command for machine-readable output, or `--csv` on list commands for a
spreadsheet: `cost --csv suppliers list > suppliers.csv`. `cost <group> --help`
lists every command and option.

## Python

```python
from costcrunch import CostCrunch

cc = CostCrunch()                                   # your `cost auth login`, or COSTCRUNCH_API_KEY
# cc = CostCrunch(api_key="cc_live_...")            # or pass a key from Settings › API
for d in cc.documents.list(status="needs_attention")["items"]:
    print(d["date"], d["supplier"], d["total"], d["url"])

sheetrock = cc.materials.find("5/8 sheetrock")["items"][0]
history = cc.materials.history(sheetrock["id"], since="2026-01-01")
print(history["summary"]["avg_price_per_unit"], history["summary"]["unit"])
```

For scripts and CI, use an API key (`COSTCRUNCH_API_KEY`) instead of signing in.
Errors raise `costcrunch.ApiError` (with `.status`, `.code`, `.message`), `NotFound`,
`PermissionDenied` or `AuthError`.

## AI assistants (MCP)

The quickest setup is in CostCrunch under **Settings › Connections › API**: create a key and copy
the ready-made command for Claude Code, Claude Desktop or Cursor. They run the server with
[uv](https://docs.astral.sh/uv/), so there's nothing to install first:

```sh
claude mcp add costcrunch --env COSTCRUNCH_API_KEY=cc_live_... -- uvx --from costcrunch cost mcp
```

If you've installed the CLI and signed in, it can print the setup for your own sign-in instead:

```sh
cost mcp setup claude-code                         # prints: claude mcp add costcrunch -- /path/to/cost mcp
cost mcp setup claude-desktop                      # prints the JSON for claude_desktop_config.json
cost mcp setup cursor
```

The server runs on your computer (`cost mcp`, over stdio), as you or as your API key. It exposes 20
read-only tools such as `search_all`, `documents_list`, `materials_find`, `materials_history`,
`materials_prices`, `projects_get` and `spend_monthly`, and every result carries a link back
into the CostCrunch app.

## Security

* You sign in as yourself. The API decides which company's data you can see from your
  membership; the `--org` option only chooses between companies you already belong to.
* This package can't change anything: there are no write operations in this version, and the
  API refuses anything but reads from an API key.
* Only a hash of each API key is stored by CostCrunch; the key is shown once. Revoking it in
  Settings › Connections › API stops it within a minute.
* Tokens are stored with `0600` permissions and refreshed automatically. The public Supabase
  key embedded in the package is the same one the web app ships with.

## Developing

```sh
uv venv && uv pip install -e '.[dev]'
pytest && ruff check src tests
```

Each operation lives in `src/costcrunch/ops/<group>.py`:

```python
@op("suppliers", "get")
def get_supplier(api, supplier_id: Annotated[str, Arg("Supplier id", positional=True)]):
    """Get one supplier: spend, branches and sales rep."""
    return pick(api.get(f"/suppliers/{supplier_id}")["supplier"], {...})
```

That one function becomes `cc.suppliers.get(...)`, `cost suppliers get <id>` and the MCP
tool `suppliers_get`. The docstring is the help text and tool description. Its first sentence
is the short summary, so write it for a customer. Results are reshaped with `pick` so internal
fields (storage paths, bounding boxes, flags) never leak out and the output doesn't change when
the web app's payloads do. `tests/test_registry.py` enforces the conventions.

Writes are supported by the registry (`@op(..., write=True)`). The CLI asks for confirmation
(or `--yes`), Python needs `confirm=True`, and the MCP tool requires a verbatim
`user_confirmation`. None are exposed yet.
