A private, local-first assistant for the Portuguese tax obligations of a self-employed professional, focus on CIRS category B.
- Node 22.18 or newer (
node --version). The CLI runs TypeScript directly through Node's type stripping: no build step, no bundler, no runtime dependency. - A browser, for the local panel.
- Full-disk encryption, if you have it. The vault is not encrypted at rest yet
(see
docs/PRIVACY-SECURITY.md§3), so the operating system's disk encryption is the control that protects it today.
git clone <this repository> vn-finance
cd vn-finance
npm install # only TypeScript and @types/node, for development
npm run verify # strict typecheck + 168 testsnpm run verify is the gate. It should end with # pass 168 and # fail 0.
node src/cli.ts # or: npm run dev — opens the local panel in your browsernode src/cli.ts doctor
node src/cli.ts agenda # next 90 days, then the rest of the year
node src/cli.ts agenda --horizon 180 # a wider plan
node src/cli.ts agenda --all # include completed, N/A and history
node src/cli.ts agenda --json # machine readable
node src/cli.ts flags
node src/cli.ts flags --json
node src/cli.ts ledger add --base 1200 --client "ACME, Lda." --nif 501234560
node src/cli.ts ledger add --base 4200 --client "Helsinki Labs Oy" --country FI
node src/cli.ts ledger add --base 900 --client "Studio Mira" --retention 0 --paid
node src/cli.ts ledger list
node src/cli.ts ledger import ~/Downloads/fatura-recibo-2026-014.pdf
node src/cli.ts ledger import fatura.pdf --dry-run # read it, write nothing
node src/cli.ts estimate # per quarter + reserve
node src/cli.ts estimate --quarter 3 # one quarter
node src/cli.ts estimate --despesas 5000 # + the IRS tax base
node src/cli.ts vault add ~/Documents/comprovativo-iva-t3.pdf \
--kind comprovativo --obligation iva.dp.trimestral
node src/cli.ts vault listDefault: ~/.vn-finance (%USERPROFILE%\.vn-finance on Windows).
The folder actually in use is decided in this order: --vault <dir> or
--data-dir <dir> on the command line, then VN_FINANCE_DATA_DIR, then the folder
you chose once and the application remembered, then the default above. The
remembered choice lives in ~/.vn-finance/vault-location.json, never inside a vault:
a file that says where the vault is cannot live in the place you would have to find
first.
Change it from the panel: Cofre de documentos → Mudar de pasta…. Or from the command line:
node src/cli.ts vault where # which folder, and why that one
node src/cli.ts vault set "C:\Users\eu\Documents\vn-finance"profile.json your profile
ledger/invoices.jsonl append-only invoice ledger
obligations/completions.jsonl obligations you marked as handled
documents/index.json document index, with SHA-256 hashes
documents/<hash>-<name> the archived copies
audit/audit.jsonl append-only audit log
ai/deepseek.key the encrypted API key, if you set one
rules/proposals-<year>.json a pending rule update, before you approve it
Two interfaces over one deterministic core, one optional AI layer, and a single arrow that leaves this machine.
The layers.
flowchart LR
subgraph UI["Interfaces"]
CLI["CLI vnfin"]
WEB["Painel local<br/>127.0.0.1 e token"]
APP["App Tauri<br/>mais tarde"]
end
subgraph CORE["Núcleo determinÃstico"]
CAL["Motor de obrigações"]
EST["Cálculos IVA SS IRS"]
RULES[("Pacote de regras<br/>pt/2026.json")]
VAULT[("Cofre local<br/>JSONL e ficheiros")]
end
subgraph AI["Camada de IA opcional"]
RED["Gateway de redação"]
DS["DeepSeek API"]
end
CLI --> CAL
WEB --> CAL
APP --> CAL
CLI --> EST
WEB --> EST
CAL --> RULES
CAL --> VAULT
EST --> RULES
EST --> VAULT
CLI --> RED
WEB --> RED
RED -->|só após aprovação| DS
The only request that ever leaves this machine: the rule pack, and nothing else.
sequenceDiagram
autonumber
actor U as Utilizador
participant P as Pacote de regras
participant G as Gateway de redação
participant D as DeepSeek
U->>P: vnfin update
P->>G: Nomes de variáveis e valores atuais
Note over U,P: Sem dados pessoais no pedido
G->>D: Payload de lei pública
D-->>G: JSON com valores e fontes
G->>G: Valida unidade e ordem de grandeza
G->>P: Grava proposta no cofre local
Note over U,P: O pacote não é alterado
U->>P: Aprova como por confirmar
Note over U: Só uma pessoa confirma
MIT. See LICENSE.