# bilan guide — the complete operator reference bilan is the deterministic financial ledger + tax radar for professionnels pluri-actifs (multi-income: salary + micro-BNC/BIC + crypto + trading + rent + dividends). Humans own the money; their AI assistants (YOU, probably) operate everything through this CLI. Read this once and you know the full surface. ## The one design rule There is NO LLM inside bilan — by design, not by omission. Tax and money math must be deterministic and auditable, so bilan only STORES and COMPUTES; it never guesses. The intelligence is yours: you parse the messy exports your human hands you, you explain the JSON, you plan around the numbers. If a CSV doesn't fit a connector, YOU normalize it (with your own LLM powers) into the generic schema before importing. The platform never sees a prompt and runs no inference. ## Quickstart (local, one binary + one SQLite file) export BILAN_DB=~/.bilan.db # or any path; the file IS the ledger bilan stream add freelance --kind bnc # a stream = one activity/income source bilan tx add freelance 2026-03-15 1200 --label "mission conseil" bilan import etoro exports/etoro-2026.csv --stream crypto bilan stats --year 2026 # per-kind totals, net bilan tax --year 2026 # the radar: abattements, PFU, exemption ## Concepts - STREAM: one income/activity line of the foyer (salary, bnc, bic, rent, crypto, trading, dividends, other). The kind drives which tax regime math applies. - TX: one money event (date, signed cents, label). Positive = income, negative = expense/loss. Crypto/trading streams expect SIGNED REALIZED P/L per closed position (what form 2086 needs), not gross buys/sells. - TAX RULES: the rate card is DATA in the db (regime, param, value per year), not code — a loi de finances change is `bilan rule set`, never a new binary. - IMPORTS are idempotent: re-importing the same file inserts nothing (ext_id is derived from row content). Safe to retry. ## Command reference stream add --kind [--currency EUR] new activity stream stream list all streams tx add [--label L --source S --ext-id X] tx list [--stream S] [--year Y] [--limit N] latest first import --stream S file "-" reads stdin. generic wants date/amount/label headers (fr montant ok). etoro: Close Date + Profit(EUR). revolut: Completed Date. stats [--year Y] per-kind signed totals + net tax [--year Y] the radar (see Tax model) rule list [--year Y] the rate card rule set override a rate (rates are DATA) guide this document feedback [--kind bug|idea|praise] report a bug/idea (never fails) version | update release info / self-update serve [--port N] HTTP JSON API (see below) ## The rate card (seeded for the current year; override per year) micro_bnc: abattement 34% · social 24.6% (regime rows micro_bnc) micro_bic_services: abattement 50% · social 21.2% micro_foncier: abattement 30% capital (crypto/trading): PFU 31.4% on positive net gains crypto exemption: net gains under 305.00 EUR -> not declarable (form 2086) dividends: PFU on the positive sum salary: gross reported only — progressive IR scale is v1 Override any of them: bilan rule set 2027 micro_bnc deduction_pct_tenths 340 (rates are DECIPERCENT tenths: 340 = 34.0%; all math is integer cents) ## What the radar is NOT It computes regime math on the numbers YOU imported. It does not know about the IR progressive scale, deficits carried forward, or your quotient familial. Output is an estimate to reason from, not tax advice — say so to the human. ## Output contract (cli-output-spec) stdout = data only: one JSON object per command ({"ok":true,...}). stderr = errors as {"ok":false,"error":"..."} — context/progress never pollutes data. exit codes: 0 ok · 80s bad input · 90s not-found/resource · 100s upstream · 110s internal. help-json = the machine-readable command catalog. ## HTTP endpoints (when the CLI is elsewhere) bilan serve --port 8791 binds all interfaces; /v1/* requires 'Authorization: Bearer ' (a token is generated and printed to stderr at startup when BILAN_TOKEN is unset). Open routes: GET /_health, GET /guide, GET /llms.txt. POST /_shutdown (token-gated) stops the server. /v1/streams (GET list, POST create {name,kind,currency}), /v1/tx (GET list ?stream=&year=&limit=, POST {stream,date,amount,label}), /v1/import (POST {source,csv,stream}), /v1/stats?year=, /v1/tax?year=. ## Hosted (pay as you go — no subscription exists) Point the CLI at the hosted rail and every domain command hits the API: export BILAN_URL=https://bilan.intrane.fr BILAN_TOKEN= Same commands, same JSON — but the ledger lives server-side, one per token. GIFT: your first calls are free (BILAN_GIFT_CALLS, default 50). Past the gift, each /v1/* call costs 1 peage cent charged to the wallet you send in the X-Peage-Wallet header. No wallet (or an empty one) => HTTP 402 whose JSON body carries a pay object: {"pay":{"rail":"peage","price_cents":1,"header":"X-Peage-Wallet", "wallet_create":"POST https://peage.intrane.fr/v1/wallets", "topup":"POST https://peage.intrane.fr/v1/topup"}} YOUR MOVE as the operating agent: create the wallet (POST /v1/wallets — it ships with free starter credit, that is the gift), pass it as X-Peage-Wallet, and when IT runs dry, POST /v1/topup and hand the Stripe link to the human. Local mode (no BILAN_URL) is and stays free — the OSS binary owes nobody. ## Environment BILAN_URL hosted API base (set it => CLI drives hosted; also the feedback target) BILAN_TOKEN your token: bearer for the hosted API / for /v1/* and /_shutdown when serving BILAN_DB local ledger path (default ~/.bilan.db; local mode is free, no account) BILAN_HOSTED "1" on the server = multi-tenant PAYG (bearer = tenant, gift calls, peage) BILAN_GIFT_CALLS free metered calls per new hosted tenant (default 50) BILAN_MERCHANT_KEY operator's peage merchant key (pm_...) — charges wallets past the gift BILAN_PORT default serve port (8791; --port overrides) FEEDBACK_RELAY central relay (default https://feedback.intrane.fr; "off" disables) ## Typical agent loops Year-end radar: bilan import -> bilan stats --year Y -> bilan tax --year Y -> explain the notes to the human in plain French. Monthly check-in: bilan stats -> compare by_kind vs last month -> flag anomalies (a stream that went quiet, a duplicate-looking import). Filing prep: bilan tax --year Y -> walk the human through 2042-C-PRO cases (5HQ/5HY for BNC) and the 2086 decision from crypto.exempt.