Metadata-Version: 2.5
Name: spendsignal
Version: 0.7.0
Summary: A small local-first library for logging line-item purchases with your own retrospective outcomes, and retrieving that history when you're about to buy something similar.
Project-URL: Homepage, https://github.com/YemaneSG/SpendSignal
Project-URL: Issues, https://github.com/YemaneSG/SpendSignal/issues
Project-URL: Source, https://github.com/YemaneSG/SpendSignal
Project-URL: Changelog, https://github.com/YemaneSG/SpendSignal/blob/main/CHANGELOG.md
Author: Yemane
License-Expression: MIT
License-File: LICENSE
Keywords: evidence,local-first,personal-finance,personal-informatics,purchase-history,receipts
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pydantic<3,>=2.5
Provides-Extra: actual
Requires-Dist: actualpy>=0.20; extra == 'actual'
Provides-Extra: all
Requires-Dist: actualpy>=0.20; extra == 'all'
Requires-Dist: invoice2data>=1.0; extra == 'all'
Requires-Dist: mcp>=1.0; extra == 'all'
Provides-Extra: extract
Requires-Dist: invoice2data>=1.0; extra == 'extract'
Provides-Extra: match
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Provides-Extra: retrieval
Description-Content-Type: text/markdown

# SpendSignal

A deterministic behavioral feedback loop for personal purchases.

`v0.7.0` · [PyPI](https://pypi.org/project/spendsignal/) · Private (in development)

---

## The loop

```
purchase (item level)
  → reflect  — answer questions about each item
  → knowledge base grows
  → deterministic engine — same input, same output, always
  → query your own history
  → answer grounded in your behavior
```

Run the full loop right now with the demo data:

```bash
pip install spendsignal

# 1. What does my history say about protein powder? (uses committed demo data)
spendsignal summarize --purchases fixtures/purchases.jsonl \
  --feedback fixtures/feedback.jsonl --subject protein-powder

# 2. Have I bought anything like protein powder?
spendsignal retrieve --purchases fixtures/purchases.jsonl \
  --feedback fixtures/feedback.jsonl --query "protein powder"

# 3. Answer questions — build your own knowledge base
spendsignal reflect --purchases fixtures/purchases.jsonl \
  --feedback fixtures/feedback.jsonl

# 4. Summarize again — your answers are now in the output
spendsignal summarize --purchases fixtures/purchases.jsonl \
  --feedback fixtures/feedback.jsonl --subject protein-powder
```

The fourth command returns different output than the first. Your feedback changed it. That is the loop.

Clone the repo to run the demo commands against the committed fixtures:

```bash
git clone git@github.com:YemaneSG/SpendSignal.git && cd SpendSignal
```

---

## Your Amazon data

Amazon lets you download your full order history as a CSV with real item-level detail.

```
amazon.com → Account & Lists → Download Order Reports → Request Report → Download
```

```bash
# One command: converts your orders to SpendSignal format
spendsignal ingest --csv ~/Downloads/amazon-orders.csv

# Same loop, your real data
spendsignal reflect
spendsignal retrieve --query "protein powder"
spendsignal summarize --subject protein-powder
```

No bank credentials. No receipt photos. No API keys.

---

## How it works

**Four JSON schemas** in [`schemas/`](schemas/) define the contracts. Same input in, same output out.

```
purchase-event        → what you bought and what was in the basket
reflection-exposure   → when you were asked about an item
feedback-event        → your answer (worth_it, would_buy_again, still_using)
evidence-summary      → the deterministic output of querying your knowledge
```

The engine lives in [`src/spendsignal/aggregate.py`](src/spendsignal/aggregate.py). It takes event streams, resolves supersession (you can change your mind — old answers are preserved), and returns an `EvidenceSummary` with coverage, per-axis distributions, contradictions, contributing event IDs, and explicit abstention when evidence is insufficient.

It never invents a score. Missing evidence = explicit abstention, not a guess.

---

## License

MIT. See [LICENSE](LICENSE).
