Skip to content

paperfoot/invoice-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

invoice-cli

Beautiful invoices from the CLI — international, stateful, agent-friendly.

A stateful, single-binary CLI for generating, tracking, and rendering invoices. Built for humans who want a clean terminal workflow and for AI agents that need a deterministic JSON interface to bill clients on their owner's behalf.

Why

Most invoice tools fall into two camps:

  • Full accounting suites (Xero, Wave, QuickBooks) — powerful but overkill if you just need to send a beautifully-branded invoice.
  • Static generators (typst templates, LaTeX invoices) — gorgeous output but no state: you re-type client details every time, numbering drifts, and an agent can't "render last month's invoice".

invoice-cli sits between them: a stateful SQLite store of issuers, clients, products and invoices, a small set of beautiful Typst templates, and a JSON interface built for agents.

Features

  • Multi-issuer first-class. Run several companies (SG Pte. Ltd., UK Ltd., US LLC, …) from one binary. Each issuer has its own jurisdiction, tax profile, default template, numbering series, and logo. New issuers default to {issuer}-{year}-{seq:04} numbering so invoice IDs stay globally addressable for agents even when several companies share one database.
  • Per-client defaults. Pin a default issuer and/or template per client — then just invoice invoices new --client meridian --item design and the right entity + branding lights up automatically.
  • International tax profiles. Built-in: Singapore GST 9%, UK VAT 20%, US (state-variable), EU VAT, plus a custom profile. Reverse-charge flag for EU cross-border B2B — rendered on the PDF with the legally-required callout.
  • Precise money math. Amounts stored as i64 minor units; tax math uses rust_decimal — no float rounding artefacts. Discount math clamped at zero so a mis-sized fixed discount can't flip totals negative.
  • Discounts at line or invoice level (rate or fixed amount).
  • Five polished Typst templates out of the box: vienna, helvetica-nera, tiefletter-gold, monoline, boutique. Self-contained — single binary, templates are embedded and extracted on first use.
  • Logos per issuer. Attach a PNG/SVG/JPG and each template renders it in the header at the appropriate size for its design language.
  • Credit notes. Issue against any existing invoice with credit-note --full (full reversal) or --item ... (specific refund lines). Independent CN-{issuer}-YYYY-NNNN numbering series so credit notes don't collide with invoices.
  • Draft-only editing. Amend a draft's metadata with invoices edit or its line items with invoices items add|remove|edit. Once issued, invoices are immutable — the correct path for corrections is a credit note, which preserves the audit trail and number-sequence integrity required by SG/EU/UK regulations.
  • QR pay-links. Set --pay-link https://buy.stripe.com/... on an invoice and the renderer stamps a scan-to-pay QR on the PDF.
  • Lifecycle timestamps. mark issued / mark paid auto-stamp issued_at / paid_at (idempotent, first-transition-only).
  • Aging + CSV export. invoices aging buckets unpaid invoices into 0-30/31-60/61-90/90+ days overdue. invoices export --from X --to Y --format csv gives you a clean accountant handoff.
  • Agent-friendly. Every command emits a JSON envelope when piped or --json; invoice agent-info returns a capability manifest; structured error codes with suggestions; exit codes distinguish transient vs permanent failures. Install the embedded Claude/Codex/Gemini skill with invoice skill install.

Install

Homebrew (macOS / Linux)

brew tap 199-biotechnologies/tap
brew install invoice

Cargo

cargo install invoice-cli

From source

git clone https://github.com/paperfoot/invoice-cli
cd invoice-cli
cargo install --path .

All install paths produce a single invoice binary. Typst is the only runtime dependency (brew install typst on macOS).

Quick start

# 1. Register your billing entity (with logo + bank details)
invoice issuer add acme \
    --name "Acme Studio" --jurisdiction sg --tax-registered \
    --tax-id "M2-1234567-8" --address "1 Marina Bay\nSingapore 018989" \
    --template boutique --logo ~/Pictures/acme.png \
    --bank-line "Bank: DBS" --bank-line "IBAN: SG11DBSS..." \
    --bank-line "SWIFT: DBSSSGSG"

# 2. Add a client, pinning acme as their default issuer
invoice clients add meridian \
    --name "Meridian & Co." --country US \
    --address "530 5th Ave\nNew York, NY 10036" \
    --default-issuer acme --default-template boutique

# 3. Register a reusable line item
invoice products add design \
    --description "Creative direction" --unit project \
    --price 8400 --currency SGD --tax-rate 9

# 4. Create an invoice — no --as needed, uses client's default issuer
#    (or config.default_issuer if the client has no pinned issuer)
invoice invoices new --client meridian --item design --due 30d

# 5. Render + open
invoice invoices render acme-2026-0001 --open

# 6. Later: mark paid, clone for next month
invoice invoices mark acme-2026-0001 paid
invoice invoices duplicate acme-2026-0001

# 7. Need a refund? Credit note against the original. Positive refund
# specs are stored as credits automatically:
invoice invoices credit-note acme-2026-0001 --item "Refund:1:500" --notes "Goodwill credit"

# 8. Month-end accountant handoff
invoice invoices export --from 2026-01-01 --to 2026-03-31 --format csv --out q1.csv

Core commands

Command Purpose
issuer add|edit|list|show|delete Manage billing entities (your companies)
issuer set-template <slug> <tmpl> Shorthand to change an issuer's default template
clients add|edit|list|show|delete Manage clients (who you bill)
clients set-issuer <slug> <issuer> Pin default issuer for a client
clients set-template <slug> <tmpl> Pin default template for a client
products add|edit|list|show|delete Manage reusable line items
invoices new --client X --item Y Create a new invoice
invoices edit <number> Edit draft metadata (due, terms, notes, discount…)
invoices items add|remove|edit <number> Mutate line items on a draft invoice
invoices duplicate <number> Clone an invoice as a fresh draft (recurring billing)
invoices credit-note <number> Issue a credit note against an existing invoice
invoices render <number> [--template T] [--open] Generate PDF
invoices mark <number> draft|issued|paid|void Update status (auto-stamps timestamps)
invoices list [--status X] [--as Y] [--overdue] List invoices with totals
invoices aging [--as Y] Aging buckets for unpaid invoices
invoices export --from X --to Y --format csv|json Accountant handoff
invoices delete <number> [--force] Delete an invoice (--force for non-draft)
template list|preview <name> Inspect available templates
doctor Diagnose typst install, DB, templates, default issuer, numbering
agent-info Full JSON capability manifest
skill install Install embedded Claude/Codex/Gemini skill
update [--check] Self-update via brew or cargo

Run invoice --help for the full reference or invoice <subcommand> --help for any subcommand.

Template resolution

At render time, the template chain is:

--template flag  >  client.default_template  >  issuer.default_template  >  "vienna"

So pinning a template on a client gives them consistent branding without you having to pass --template every time.

Item specs

On invoices new, each --item is one of:

  • product-slug — uses the product's price, unit, and tax rate
  • product-slug:qty — e.g. design:2 for two units
  • "Description:qty:price" — ad-hoc item with default tax rate from jurisdiction
  • "Description:qty:price:rate" — ad-hoc item with explicit tax rate

State & privacy

  • Config: shared Paperfoot accounting config. Run invoice config path for the exact OS path; on macOS it lives under ~/Library/Application Support/com.paperfoot.accounting/.
  • Database: shared Paperfoot accounting SQLite database (accounting.db in the shared state dir; invoice agent-info reports the exact path).
  • Templates: extracted once to the state dir, refreshed on upgrade

Nothing ever leaves your machine unless you choose to — no telemetry, no phone-home, no cloud sync.

Agent usage

This CLI is designed to be driven by AI agents as well as humans. The contract:

  • Every command emits a {version, status, data|error} envelope when piped.
  • invoice agent-info returns a full capability + exit-code manifest.
  • invoice doctor --json reports setup, default issuer validity, and risky multi-company numbering formats.
  • invoice skill install drops a ready-to-use skill file into ~/.claude/skills/invoice-cli/SKILL.md (and the Codex/Gemini equivalents).

Typical agent workflow:

USER:  "Bill Meridian for last month's design work"
AGENT: invoice invoices duplicate $(invoice invoices list --json | jq -r '.data[0].number')

Agents should use invoice numbers returned by JSON responses, not predict the next sequence. The CLI keeps numbers globally unique; if legacy issuers share a plain {year}-{seq:04} format, generation auto-prefixes the issuer slug on collision and doctor warns so you can clean up the formats.

Architecture

  • Rust binary via cargo / single-binary distribution.
  • SQLite via rusqlite with refinery migrations (migrations/V*.sql).
  • Typst for PDF rendering — templates live in typst/, embedded via rust-embed and extracted to the user's state dir.
  • Money as i64 minor units; tax with rust_decimal. No floats in financial paths.
  • Built on agent-cli-framework (ACF) conventions for agent ergonomics.

Scope

This is an invoicing tool, not an accounting suite. In scope:

  • Clean, branded invoice generation across multiple entities
  • Multi-currency, multi-jurisdiction tax handling
  • Lifecycle tracking (draft → issued → paid → void)
  • Recurring billing via duplicate

Explicitly out of scope:

  • Double-entry bookkeeping
  • Bills payable / accounts payable
  • Bank reconciliation
  • GST/VAT filing reports
  • Chart of accounts, P&L, balance sheet
  • Payroll, inventory, expense tracking

For those, reach for Xero, Wave, or QuickBooks.

License

MIT © 199 Biotechnologies