feat: fin CLI + agent skill + opt-in API bearer auth
Adds `fin` — a typer/httpx CLI for the deployed API — so Claude Code and
other agents can consume fin over HTTP without an MCP server.
Backend:
- api/app/auth.py: require_api_token dependency (no-op unless FIN_API_TOKEN
env is set; RFC 7235 case-insensitive Bearer, constant-time compare). All
nine routers wired; /api/health exempt for k8s probes.
- GET /api/openapi.json added as an explicit token-gated route (FastAPI's
built-in openapi_url bypasses dependency injection).
- GET /api/transactions gains an optional `limit` query param (ge=1).
CLI (cli/):
- fin_cli/client.py: FinClient — sync httpx wrapper, zero typer/rich imports
(MCP-ready core for a future MCP server).
- Subcommands: networth, accounts, categories, tx, transfer, settle,
split-expense, splitwise-paid, reconcile, holdings, stock, rsu,
spending, prices. Every command supports --json for agent use.
- fin tx add refuses transfer/settlement types to prevent single-leg writes.
- Config via FIN_API_URL (required) and FIN_API_TOKEN (optional).
Agent skill: .claude/skills/fin/SKILL.md — command map, jq patterns, and
domain invariants (two-leg atomicity, net-share splitwise math, derived
holdings, funded-buy, soft-deactivate, FIN_API_TOKEN web-UI lockout warning).
Tests: 25 e2e tests (FinClient → real routes → temp SQLite) covering auth
on/off, all key invariants (two-leg linkage, fee-in-balance, net-share math),
transfer whole-group delete, and linked-leg edit rejection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPBt3s7Jyr2nozQTrVVGA4