Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ By participating in this project, you agree to be respectful and constructive in
### Reporting Issues

1. **Search existing issues** to avoid duplicates
2. **Use issue templates** when available
2. **Open a focused issue** with a clear title
3. **Provide context**: Include OS, Python version, and steps to reproduce
4. **Be specific**: Clear descriptions help us fix issues faster

Expand All @@ -36,7 +36,7 @@ uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate

# Install development dependencies
uv install
uv sync --dev

# Run tests to verify setup
uv run pytest
Expand All @@ -60,7 +60,7 @@ uv run pytest
uvx ruff check

# Type checking
uvx ty
uvx ty check

# Run tests
uv run pytest
Expand Down Expand Up @@ -116,7 +116,7 @@ We follow conventional commits:

## Pull Request Process

1. **Fill out the PR template** completely
1. **Explain the user-facing change** and any privacy implications
2. **Link related issues** using keywords (fixes #123)
3. **Ensure CI passes** all checks
4. **Respond to feedback** promptly
Expand All @@ -136,7 +136,7 @@ We follow conventional commits:

```bash
# Run in development mode
uv run python run_dev.py
uv run fafycat serve --dev

# Reset with sample data
uv run python scripts/reset_and_import.py --dev-mode --use-sample-data
Expand All @@ -157,10 +157,8 @@ uv run python scripts/train_model.py

## Getting Help

- **Discord**: [Join our community](https://discord.gg/fafycat) (if available)
- **Discussions**: Use GitHub Discussions for questions
- **Issues**: For bugs and feature requests
- **Email**: contributors@fafycat.org (if available)
- **Issues**: Use GitHub Issues for bugs and feature requests
- **Discussions**: Use GitHub Discussions if enabled for broader questions

## Recognition

Expand All @@ -171,8 +169,8 @@ Contributors are recognized in:

## License

By contributing, you agree that your contributions will be licensed under the MIT License.
By contributing, you agree that your contributions will be licensed under the Apache License 2.0.

---

Thank you for helping make FafyCat better for everyone!
Thank you for helping make FafyCat better for everyone!
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 🐱 FafyCat - Local-First Transaction Categorization

FafyCat is a privacy-focused financial transaction categorization tool that uses machine learning to automatically organize your banking data with >90% accuracy. All processing happens locally on your device - no cloud services, no data sharing.
FafyCat is a privacy-focused financial transaction categorization tool that uses local machine learning to organize your banking CSV exports. Your transaction data stays on your device: no account linking, no hosted backend, and no cloud copy of your financial history.

<p align="center">
<img src="docs/media/fafycat-demo.gif" alt="FafyCat demo showing the workflow from import to review and analytics" width="100%">
Expand All @@ -18,8 +18,8 @@ FafyCat is a privacy-focused financial transaction categorization tool that uses

## ✨ Key Features

- **🤖 Smart Categorization**: Machine learning automatically categorizes transactions with high accuracy
- **🔒 Privacy First**: All data stays on your device - no external APIs or cloud services
- **🤖 Smart Categorization**: Machine learning categorizes transactions from your own reviewed history
- **🔒 Privacy First**: Transaction data stays on your device, with local static assets and no hosted backend
- **📊 Intelligent Review**: Active learning reduces manual work by 70-90%
- **🏪 Merchant Memory**: Learns from your patterns to improve over time
- **📈 Export Ready**: Multiple export formats for your favorite analysis tools
Expand Down Expand Up @@ -163,7 +163,8 @@ Common bank formats supported:
### Privacy & Security

- **Local Processing**: All ML models run on your device
- **No Cloud Services**: Zero external API calls
- **No Account Linking**: Import CSV exports instead of connecting bank accounts
- **No Hosted Backend**: The web UI is served by your local FafyCat process
- **Your Data**: You own and control all your financial data
- **Open Source**: Fully auditable codebase

Expand Down Expand Up @@ -207,7 +208,7 @@ FAFYCAT_HOST=127.0.0.1

## 📈 Performance

- **Accuracy**: >90% correct categorization
- **Accuracy**: Designed to improve from your reviewed transactions; results depend on your data quality and category history
- **Speed**: <100ms per transaction
- **Scale**: Handles 100,000+ transactions
- **Efficiency**: 70-90% reduction in manual review
Expand Down Expand Up @@ -250,7 +251,7 @@ All shipped application code lives under `src/fafycat/`:

## 🤝 Contributing

tbd.
Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for setup, quality checks, and pull request expectations.

## 📄 License

Expand Down
119 changes: 119 additions & 0 deletions docs/coding-agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Using FafyCat with a coding agent

FafyCat ships a small read-only CLI surface designed for use by coding agents like Claude Code, Cursor, or any tool that can shell out and read JSON. This guide shows how to wire it up and what the agent can do.

The CLI never mutates your data. It only reads from your existing FafyCat database. Imports and re-categorization still happen through `fafycat import` and the web UI.

## Why a separate CLI for agents?

The web UI is built for humans. Agents need:

- **Stable, machine-parseable output.** Every read-only command prints JSON to stdout (`indent=2`, exit 0) or `{"error": "..."}` (exit 1). No prose, no spinners, no ANSI.
- **Predictable flags.** Date filters, pagination, and category filters all share the same shape across commands.
- **No browser.** Works inside any agent loop without launching the FastAPI server.

If you only ever want to ask "what did I spend on groceries last month?" from inside an editor, this is enough. You do not need to keep `fafycat serve` running.

## One-time setup

1. Make sure FafyCat is installed and you have at least one CSV imported. See the main [README](../README.md) for the install path.
2. Verify the CLI sees your data:
```bash
fafycat cat list
```
You should get a JSON envelope with your categories.

If you keep your FafyCat database somewhere non-default, point the CLI at it with one of:

- `--data-dir /path/to/data` flag (accepted at any position: root, group, or leaf)
- `FAFYCAT_DATA_DIR` env var
- `~/.config/fafycat/config.toml` with `[paths] data_dir = "..."`

Precedence: flag > env var > config file > platform default.

## Plugging into Claude Code

FafyCat bundles a Claude Code skill that documents every command, its flags, and its response shape. Install it into your project:

```bash
fafycat skill install
```

This writes `./.claude/skills/fafycat/SKILL.md`. Claude Code auto-discovers skills in `.claude/skills/` and loads the file when you ask a finance-related question. You can also install it elsewhere:

```bash
fafycat skill install ~/myproject/.claude/skills/fafycat
fafycat skill install --force # overwrite an existing copy
```

For other agents, point them at the same `SKILL.md` — it is plain Markdown describing the CLI contract and is reusable as a system prompt or tool description.

## What the agent can do

All commands return JSON. The full reference lives in the bundled `SKILL.md`; this is a short tour.

### Inspect categories and budgets

```bash
fafycat cat list
fafycat cat list --include-inactive
fafycat budget show 2025
```

`budget show` returns `has_year_specific_budgets: false` when every entry is a fallback (the year was never explicitly budgeted). Treat that the same as "year not budgeted".

### Query transactions

```bash
fafycat tx list --month 2025-01
fafycat tx list --ytd --category Groceries --limit 50
fafycat tx list --unreviewed --last-n-months 3
```

Pagination: `--skip`, `--limit` (default 20, cap 500). Response envelope includes `total_count` and `has_next`.

### Analytics

```bash
fafycat analytics monthly --year 2025
fafycat analytics breakdown --ytd --type spending
fafycat analytics variance --year 2025
fafycat analytics savings --year 2025
fafycat analytics yoy --type spending --years 2023,2024,2025
fafycat analytics top --year 2025 --month 3
```

`--type` on `breakdown` accepts exactly `income`, `saving`, or `spending` — anything else exits with code 2.

### Date flags (shared across commands)

All mutually exclusive with each other and with `--start`/`--end`:

- `--month YYYY-MM`
- `--year YYYY`
- `--this-month`
- `--last-month`
- `--ytd`
- `--last-n-months N`

## Working patterns

A few prompts that work well:

- *"How does my YTD spending compare to budget?"* — agent runs `fafycat analytics variance --ytd` and summarises.
- *"What were my five biggest expenses last month?"* — agent runs `fafycat analytics top --last-month`.
- *"Find any unreviewed transactions over 100 EUR in the last 3 months."* — agent runs `fafycat tx list --unreviewed --last-n-months 3 --limit 500` and filters client-side.
- *"Build me a year-end summary notebook."* — agent runs `analytics monthly`, `breakdown`, `savings`, and stitches the JSON into a notebook or report.

## Boundaries

- **Read only.** There is no `tx update`, `tx delete`, `cat create`, etc. on the CLI. Agents cannot change your data through this surface. To re-categorize, send the agent to the review UI.
- **Local only.** No network calls. Your data does not leave the machine the CLI runs on.
- **No row-level personal data in shared output.** When asking the agent to write a public artefact (issue, PR, gist), tell it to keep amounts and category names generic.

## Troubleshooting

- **`{"error": "..."}` and exit 1.** Almost always a bad date flag combination, an unknown category name, or a missing database. Run `fafycat init` if the database is missing.
- **Exit code 2.** Argparse rejected the input (e.g. `--type` outside the allowed set, `--month` not in `YYYY-MM`).
- **Empty results from a freshly installed FafyCat.** Run `fafycat import path/to/file.csv` first or boot `fafycat serve --dev` to seed synthetic data.
- **Skill not picked up.** Confirm the file lives at `.claude/skills/fafycat/SKILL.md` relative to the directory you opened in Claude Code. Re-run `fafycat skill install --force` if you suspect drift.
13 changes: 13 additions & 0 deletions src/fafycat/static/vendor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Vendored Frontend Assets

FafyCat serves these browser dependencies locally so the web UI does not contact
third-party CDNs during normal use.

| File | Upstream | Version | License |
| --- | --- | --- | --- |
| `tailwind-2.2.19.min.css` | https://github.com/tailwindlabs/tailwindcss | 2.2.19 | MIT |
| `htmx-1.9.12.min.js` | https://github.com/bigskysoftware/htmx | 1.9.12 | BSD-2-Clause |
| `chart-4.4.9.umd.min.js` | https://github.com/chartjs/Chart.js | 4.4.9 | MIT |

When updating these files, keep the version in the filename and update this
table in the same change.
20 changes: 20 additions & 0 deletions src/fafycat/static/vendor/chart-4.4.9.umd.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/fafycat/static/vendor/htmx-1.9.12.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/fafycat/static/vendor/tailwind-2.2.19.min.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/fafycat/web/components/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ def create_page_layout(title: str, content: str) -> str:
<meta name="color-scheme" content="dark">
<title>{title}</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="/static/vendor/tailwind-2.2.19.min.css" rel="stylesheet">
<link href="/static/css/theme.css" rel="stylesheet">
<link href="/static/css/components.css" rel="stylesheet">
<script>document.documentElement.className='js-enabled';</script>
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<script src="/static/vendor/htmx-1.9.12.min.js"></script>
<script src="/static/js/main.js" defer></script>
</head>
<body class="antialiased">
Expand Down
2 changes: 1 addition & 1 deletion src/fafycat/web/pages/analytics_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def render_analytics_page(request: Request, session: Session) -> HTMLResponse:
</div>

<!-- Chart.js and Analytics JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="/static/vendor/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/analytics.js"></script>
<script src="/static/js/analytics_yoy.js"></script>
<script src="/static/js/analytics_page.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion src/fafycat/web/pages/settings_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ def render_budget_variance_section():
</script>

<!-- Chart.js for budget variance chart -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="/static/vendor/chart-4.4.9.umd.min.js"></script>
"""


Expand Down
Loading