You earned well this year.
Do you know where it went?
Drop your trade history into Claude.
Get back a full financial picture — portfolio, net worth, cash flow — stored in a local SQLite file.
npm install -g @evan-moon/firma
firma-demo.mp4
You: Here's my IBKR trade history [trades.csv]. Set up firma.
Claude: I see 47 transactions. Logging in chronological order... done.
Syncing prices and FX history... your portfolio: $179K, +61% all-time. TSLA is 78%.
You: My portfolio feels really volatile lately. Should I be worried?
Claude: TSLA is 74% of your equity — a 10% TSLA move is a 7% net worth move.
Cash flow is solid at $6.4k/month saved. The volatility is market, not lifestyle.
You: That July expense spike looks alarming.
Claude: That was $57k in TSLL — a leveraged bet, not spending.
Strip it out: expenses flat at ~$7k/month, savings rate 47.8%.
You: Give me a full overview with charts.
Claude: Net worth: $294k → $490k in 8 months, pulled back to $427k with TSLA's Q1 dip.
[builds net worth trend, income vs expenses, portfolio allocation, unrealized P&L]
- Talks to Claude natively.
firma mcp installwires firma into Claude Desktop. Every command you can run in the terminal, Claude can call through MCP — log trades, sync prices, render charts, reason about your data. - Local-first, no exceptions. Everything lives in
~/.firma/firma.db. No server, no sync, no account. Your financial data never leaves your machine. - Multi-market, one stored currency. Track holdings across 9 markets (US, KRX, KOSDAQ, JP, HK, LSE, XETRA, NSE, TW) — plus non-stock assets like crypto, commodities, and real estate. Every value is stored in USD and displayed in the currency you pick, with historical FX rates from FRED — so a 2018 balance shows the 2018 exchange rate, not today's.
- Transactions as source of truth. No holdings table to drift out of sync. Portfolio, cost basis, and P&L are always derived live from your trade log.
- Daily brief with world context.
get_briefbundles holdings, macro signals, commodity prices, dividend calendar, global macro (World Bank), and active disaster alerts (GDACS) in one call — no extra API keys needed for the global data. - Developer-friendly.
--jsonon every read command. Three clean verb groups:add,show,report.
Two ways to install — both work the same way once set up.
Download and double-click. Node.js is bundled — nothing to install first. API keys are configured via setup dialogs (opens Finnhub + FRED in your browser, then prompts you to paste each key). Claude Desktop is connected automatically.
↓ Download firma-mac-arm64.pkg
# 1. Install
npm install -g @evan-moon/firma
# 2. Set API keys (both free)
firma config set finnhub-key YOUR_KEY # finnhub.io — prices, news, earnings
firma config set fred-key YOUR_KEY # fred.stlouisfed.org — macro & FX history
# 3. Connect Claude Desktop
firma mcp install
# Restart Claude Desktop — firma tools will appear in the toolbar.Drop your data into Claude. Paste a CSV, brokerage export, or plain text — Claude logs everything and syncs prices automatically.
Prefer the terminal? Every MCP tool has a matching
firmacommand — see CLI reference.
If firma helps you track your money, please ⭐ star the repo — it's the cheapest way to help others find it.
--json is available on every read command. Alias: firma rm = firma delete.
| Command | What it does |
|---|---|
firma show portfolio |
Holdings with P&L, avg cost, market value |
firma show txns [ticker] |
Transaction history with running avg cost |
firma show dividend |
Estimated annual income + per-ticker yield |
firma show concentration |
HHI concentration by ticker, currency, sector, country |
firma show snapshot [ticker] |
Portfolio value history; --from/--to for date range |
firma show benchmark |
Portfolio return vs SPY/QQQ (or custom benchmarks via -b) |
firma show risk |
Volatility, drawdown, Sharpe, Sortino, beta — requires snapshots |
firma profile |
Set up your goals (birth year, retirement target, target net worth, risk tolerance, notes) — every field optional |
firma show profile |
Show the stored profile |
| Command | What it does |
|---|---|
firma add balance [-p YYYY-MM] |
Monthly asset & liability snapshot |
firma add flow [-p YYYY-MM] |
Monthly income & expense entry |
firma add monthly [-p YYYY-MM] |
Balance + flow in one call (month-end) |
firma show balance [-p YYYY-MM] |
Stored balance entries for a period |
firma show flow [-p YYYY-MM] |
Stored cash flow entries for a period |
firma report |
Net worth trend + cash flow charts (combined) |
firma report balance / flow / settle |
Targeted views |
firma report -c USD |
Display in any supported currency — -c also works on show portfolio, txns, balance, flow, dividend, snapshot, and brief |
| Command | What it does |
|---|---|
firma add txn |
Record a transaction — a stock in any of 9 markets, or a non-stock asset (crypto / commodity / real estate) — type buy / sell / deposit / dividend / tax |
firma add price [name] [value] |
Set the current value of non-stock holdings (they have no price feed) |
firma edit txn [id] |
Edit a transaction |
firma delete txn [id] |
Delete a transaction |
| Command | What it does |
|---|---|
firma add snapshot |
Sync prices and record today's portfolio snapshot |
firma edit snapshot |
Edit a snapshot entry (interactive picker) |
firma delete snapshot [date] |
Delete all entries for a date |
| Command | What it does |
|---|---|
firma show news <ticker> |
Recent company news |
firma show insider <ticker> |
Insider buy/sell transactions |
firma show financials <ticker> |
SEC-reported quarterly financials (income, cash flow, balance sheet) |
firma show valuation <ticker> |
PEG ratio, P/S, FCF yield — computed from 8 quarters of SEC filings |
firma show earnings [ticker] |
Earnings calendar + EPS history |
| Command | What it does |
|---|---|
firma show macro |
VIX, 10Y yield, yield curve, USD index, HY spread, inflation, fed funds, FX + Economic Stress Index (0–100) + macro regime bias (Risk-on / Mixed / Risk-off) |
firma show fx [currency] |
Inspect cached FX history with --from/--to/--limit |
| Command | What it does |
|---|---|
firma show world-intel |
World Bank macro (GDP, inflation, unemployment) + GDACS active disaster alerts in one view |
| Command | What it does |
|---|---|
firma brief |
Daily intelligence brief: movers, news, earnings, macro, commodities, dividend calendar, world macro, disaster alerts (cached per day; --refresh to regenerate) |
firma sync |
Fetch latest prices (Finnhub) + FX rate history (FRED) |
firma sync fx |
FX history only — incremental backfill from your earliest entry date |
firma doctor |
Check setup status — API keys, data, FX cache |
firma mcp install |
Register MCP server in Claude Desktop |
firma config set finnhub-key KEY |
Set Finnhub API key |
firma config set fred-key KEY |
Set FRED API key |
firma config set currency CODE |
Set home currency (KRW, USD, JPY, …) |
After firma mcp install, Claude has full read/write access to your data through conversation. Two tools are available only via MCP:
| Tool | What it does |
|---|---|
fetch_fred_series |
Fetch any FRED time series by ID (800K+ series) |
search_fred_series |
Search the FRED catalog by keyword |
get_brief is the primary entry point for any daily check-in or market question. In a single call it returns:
- Portfolio — holdings with weights, daily P&L, total cost vs market value
- Concentration — HHI by ticker, sector, currency, country
- Movers — top winners and losers for the day
- News — recent headlines per holding
- Earnings — upcoming earnings dates with EPS estimates
- Economic calendar — high/medium-impact events for the week
- Macro — FRED snapshot (VIX, 10Y yield, credit spread, fed funds, FX impact in home currency)
- Stress & Regime — Economic Stress Index + Risk-on / Mixed / Risk-off bias
- Commodities — WTI oil, gold, copper (via FRED — no extra key)
- Dividend calendar — upcoming ex-dates and estimated income for held positions
- World macro — GDP growth, inflation, unemployment across major economies (World Bank — no extra key)
- Disaster alerts — active GDACS Orange/Red events (no extra key)
- Insights — cross-referenced observations that tie portfolio exposure to macro context
If today's snapshot is missing, get_brief records one automatically before assembling the brief, so daily history accrues even when you forget to run firma add snapshot.
show_valuation and show_world_intel are available for deeper drill-downs after reading the brief.
Prompts — type / in Claude Desktop to access guided workflows:
| Prompt | What it does |
|---|---|
import-trades |
Confirms column mapping then inserts every row in a single add_txn call — handles 100s of rows in one shot |
import-balance |
Same flow for a net-worth spreadsheet (rows = months, columns = balance categories) → one add_balance call |
import-flow |
Same flow for an income/expense spreadsheet → one add_flow call |
month-end |
Walks through balance + cash flow entry for the period, submits in one batch |
morning |
Calls get_brief and surfaces only what needs attention |
analyst |
Activates a financial-analyst persona — Claude leads with concentration risk, frames every number against net worth or runway, and combines portfolio + cash flow + macro into a single view |
setup-profile |
Captures your goals (birth year, retirement target, target net worth, risk tolerance, notes) so all future analysis is anchored to them — every field optional |
pre-mortem |
Five plausible ways a position could go wrong over 12 months — concrete failure modes tied to actual data, with portfolio impact in dollars |
rebalance |
Compares current allocation against your stated target, flags drift, suggests specific trades while accounting for tax cost and wash-sale risk |
tax-harvest |
Scans unrealized losses, checks 30-day wash-sale rule, suggests similar-but-not-identical replacements, estimates tax savings by bracket |
scenario |
Models a market shock or macro shift on your actual portfolio with explicit beta assumptions you can override |
setup_status (called by Claude at the start of any conversation) also returns an analyst_context block — a lightweight version of the analyst persona that influences every reply without a manual prompt invocation.
Historical FX note: firma sync fx backfills daily FX rates (KRW, JPY, EUR, CNY, GBP, HKD, INR, TWD) from FRED starting at your earliest transaction date. Subsequent runs are increment-only. This means a 2018 balance in KRW uses the 2018 rate — not today's.
Firma is a Yarn Berry monorepo with a layered, port-and-adapter design. The application layer never imports an external-API package directly — it talks to domain interfaces, and adapters implement those interfaces against specific services.
Workspace layout reflects the layers:
packages/
domain/ ports + types + routers, no external-API dep
domain/ market/ (Quote, StockSnapshot, Candle, news, …),
macro/ (series, country indicators, live FX, stress,
regime), event/ (world disaster events)
external-api/ raw API clients, no firma-domain dep
finnhub/ fred/ worldbank/ gdacs/ open-er-api/ yahoo-finance/
adapter/ the only layer that imports both sides
adapters/ provider registry — createMarketProviders, …
use-case/ business logic
portfolio/ brief/
shared/ cross-cutting
db/ utils/
apps/
cli/ mcp/ docs/
Import dependencies (A → B means "A imports B"):
apps/cli, apps/mcp
→ @firma/adapters data-clients.ts builds providers via the registry
→ @firma/domain commands/tools call domain clients directly
for simple reads (e.g. `show news`)
→ use-case packages richer flows (portfolio sync, brief)
use-case (portfolio, brief)
→ @firma/domain
@firma/adapters
→ @firma/domain implements MarketDataProvider / MacroDataProvider /
EventDataProvider
→ external-api packages calls the raw HTTP/RSS clients
external-api (finnhub, fred, worldbank, gdacs, open-er-api, yahoo-finance)
→ shared only pure API clients; no domain/adapter knowledge
@firma/domain
→ shared only the stable core; no external-api / adapter /
use-case / app dependency
shared (db, utils)
→ nothing cross-cutting leaf; imported by every layer above
At runtime, data flows the opposite way:
External API → @firma/adapters → domain client → use-case → cli / mcp
Dependency rule: external-API packages have zero firma-domain knowledge; domain packages have zero external-API knowledge. @firma/adapters is the only package that imports both sides. Application code (apps/cli, apps/mcp) talks to domain clients; the one place it touches @firma/adapters is data-clients.ts, which constructs the concrete providers.
Capabilities — each domain interface declares a capability set; the router picks a provider per capability:
| Sub-domain | Capabilities |
|---|---|
market |
quote, snapshot, candles, news, insider, financials, earnings, dividends, economic-calendar |
macro |
series, metadata, search, country-indicator, live-fx |
event |
disasters |
Why this matters: adding a data source touches no command or business-logic code. Adding KRX coverage, for example, means a new packages/external-api/naver/ raw client, a createNaverProvider(): MarketDataProvider in packages/adapter/adapters/src/, and one registration line in packages/adapter/adapters/src/registry.ts. See CONTRIBUTING.md for the full recipe.
Requires Node.js 22+ and Yarn Berry.
corepack enable
yarn install
yarn dev:cli show portfolio # CLI dev mode
yarn typecheck # Full type check
yarn test # Run unit testsSee CONTRIBUTING.md for the full architecture walkthrough and the recipe for adding a new external data provider.
Firma is the financial intelligence layer of the Herald ambient voice assistant stack. When connected, Herald can:
- report your portfolio performance and net worth by voice
- answer "how much did I spend on fees this quarter?" without opening a spreadsheet
- surface market context mid-conversation alongside your own position data
Herald + Firma + Memex — ambient voice, financial intelligence, and persistent memory in one personal AI stack.
llms.txt is a machine-readable summary of this project for LLM agents — concise description with documentation links, following the llms.txt standard.
MIT © Evan Moon