3 Commits
Author SHA1 Message Date
EislM0203andClaude Opus 5 cb97d97d81 docs: check in the fin skill library, ignore local Claude settings
Twelve skills that had been sitting uncommitted in the working tree: the
architecture contract, accounting reference, change-control rulebook, failure
archaeology, debugging playbook, diagnostics scripts, ledger-analysis toolkit,
research frontier, run/operate runbook, build-and-env, test-coverage campaign,
and validation/QA guide.

Updates three frontier statuses to match what actually shipped today rather
than checking in a roadmap that describes closed work as open:

- A1 double-entry hardening -> partly-done. The create half is enforced; what
  remains is running the existing audit_linked_legs.py against a prod backup.
- B3 safety rails -> partly-done. Idempotency shipped, including the note that
  the index is not unique-when-not-null and why. dry_run is still open.
- D3 CSV import -> unblocked but still gated. Its stated blocker was B3's
  idempotency keys, which now exist.

Also gitignores .claude/settings.local.json, which is per-machine and was
showing up as untracked on every status.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3qYLuu9jgXsCRXmJ18YGY
2026-08-22 22:09:22 +00:00
EislM0203andClaude Opus 5 439a15264b feat: fin-mcp as a deployable HTTP service, with typed tools and name resolution
Makes the MCP server runnable as a network service and hardens its tool
surface. Previously it was stdio-only and had never been executed — the
test file had never run, and 3 of its 5 tests failed on first invocation.

Transport and deployment

  FIN_MCP_TRANSPORT selects stdio (default, unchanged) or streamable-http,
  which binds FIN_MCP_HOST:FIN_MCP_PORT and serves MCP at FIN_MCP_PATH
  (default /mcp) with stateless_http so no session affinity is needed.

  Ships as its own image (cli/Dockerfile) and its own Deployment +
  ClusterIP Service (deploy/k8s/fin-mcp.yaml) rather than being mounted
  into the API app — matching how the other MCP servers in the cluster are
  deployed, and keeping the mcp dependency out of the api image. The
  manifest is a reference to copy into the Flux repo; it is not applied
  from here.

  The manifest deliberately has no HTTPRoute. fin-mcp has no auth of its
  own and the API runs with FIN_API_TOKEN unset, so with writes enabled
  the only thing keeping it safe is being unreachable from outside the
  cluster.

Correctness

  create_transaction accepted a free-form type string while
  POST /api/transactions accepts all six transaction types. A caller
  passing type=transfer would write a single leg with no
  linked_account_id — an orphan that corrupts balances and that
  paired-delete can never clean up. All eight enum-valued parameters are
  now Literal-typed, so the client rejects such calls before they are
  made. TestInvariantGuards locks this down.

  FinClient was constructed eagerly in create_server(), so a missing
  FIN_API_URL killed the process before the MCP handshake and surfaced to
  the client only as "server failed to start". It is now built lazily on
  first use, turning the same misconfiguration into a readable error.

Tool surface

  Adds find_account / find_category, which map a name to the integer id
  every other tool requires — exact match wins, otherwise all substring
  matches are returned so the caller can disambiguate. Publishes accounts
  and categories as the resources fin://accounts and fin://categories.
  Drops get_openapi_spec: the tools already cover the API and the spec is
  too large to justify a tool slot.

  The three update_* tools took an untyped dict[str, Any], which produced
  a schema with no properties at all; they now take explicit optional
  parameters, plus clear_* flags so the ability to null a field survives
  the change.

  Removes ~48 lines of write-warning boilerplate duplicated across 24
  tools — it lives in the server instructions once, and no longer claims
  refresh_prices can double-book. Fixes fetch_ticker_price claiming it
  blocks for minutes when the client times out at 30s, and
  deactivate_account flagging itself destructive while documenting itself
  as reversible.

Tests: 37 passing, up from 27 passing / 3 failing. The failures were
harness bugs — mcp >=1.12 returns (content, structured) from call_tool
where the helper assumed a list. Verified against a live API over both
transports: handshake, reads, writes, name resolution, resource reads,
and rejection of the transfer type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3qYLuu9jgXsCRXmJ18YGY
2026-08-22 21:20:39 +00:00
EislM0203andClaude Sonnet 4.6 082b6081b7 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
2026-07-03 19:22:15 +00:00