Local-first CLI for contractor invoices from YAML files.
Project description
ivce
ivce is a local-first CLI for creating, validating, rendering, and emailing contractor invoices from YAML files.
It is designed for service invoices over explicit date ranges, with optional reimbursable expenses and PDF receipt bundles. It does not implement legal tax invoice or nota fiscal behavior.
Requirements
- Python 3.12+
- Typst CLI for PDF rendering:
brew install typst
Install
pip install ivce
The PyPI package is named ivce; it installs the ivce command.
Development Setup
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Usage
ivce init
ivce new standard 2026-06
ivce new standard 2026-08 --contractor acme --client globex --reference-profiles
ivce new standard 2026-05 --period-start 2026-05-01 --period-end 2026-05-31
ivce new standard 2026-05 --period-start 2026-05-01 --period-end 2026-05-07 --invoice-number INV-202605-W1 --output workspace/invoices/2026-05-w1.yml
ivce new reimbursement 2026-07
ivce validate workspace/invoices/2026-07.yml
ivce validate private-client/invoices/2026-07.yml --workspace private-client
ivce render workspace/invoices/2026-06.yml
ivce render private-client/invoices/2026-06.yml --workspace private-client
ivce render workspace/invoices/2026-06.yml --template classic
ivce render workspace/invoices/2026-07.yml --with-receipts
ivce email workspace/invoices/2026-06.yml --dry-run
ivce email private-client/invoices/2026-06.yml --workspace private-client --dry-run
Generated PDFs are written to workspace/dist/ by default. Rendered Typst source is written next to the PDF to make debugging template issues straightforward.
Files
workspace/invoice.yml: contractor/client defaults.workspace/contractors/name.yml: reusable contractor profiles.workspace/clients/name.yml: reusable client profiles.workspace/invoices/YYYY-MM.yml: invoice data with explicit service period dates.workspace/receipts/YYYY-MM/: optional receipt attachments.workspace/dist/: generated invoice PDFs and receipt bundles.
Receipt Formats
Receipt bundles support pdf, jpg, jpeg, png, heic, and heif receipt files. PDF receipts can contain multiple pages. Image receipts are rendered into the bundle as one receipt page per image. HEIC/HEIF support uses the macOS sips command to convert images locally before bundling.
expenses:
- date: "2026-07-03"
description: Train ticket
amount: "25.00"
receipt: receipts/2026-07/train-ticket.jpg
Examples
Public fake examples live in examples/sample-data. They cover all built-in templates, profile references, a weekly billing period, and reimbursement display modes.
ivce validate examples/sample-data/invoices/2026-06-modern.yml --workspace examples/sample-data
ivce render examples/sample-data/invoices/2026-06-modern.yml --workspace examples/sample-data
Quickstart with the included sample workspace:
ivce templates list
ivce validate examples/sample-data/invoices/2026-06-modern.yml --workspace examples/sample-data
ivce render examples/sample-data/invoices/2026-06-classic.yml --workspace examples/sample-data --output-dir /tmp/invoice-example
Templates
The CLI ships with three built-in Typst/Jinja2 templates:
modern: polished default with a branded header and summary band.classic: conservative business invoice.minimal: sparse type-driven layout for simple retainers.
List templates and render with a specific one:
ivce templates list
ivce render workspace/invoices/2026-06.yml --template modern
ivce render workspace/invoices/2026-06.yml --template-file ./templates/client.typ.j2
Template choices and branding are copied into each generated invoice so old invoices can be rerendered consistently:
template: modern
brand_color: "#1f4e79"
accent_color: "#d9e8f5"
font: New Computer Modern
Contractor and Client Profiles
Invoices can either snapshot contractor/client data or reference reusable profile files.
Reusable profiles live in:
workspace/contractors/acme.yml
workspace/clients/globex.yml
Snapshot mode is the default. It resolves profiles and copies their current values into the invoice YAML:
ivce new standard 2026-08 --contractor acme --client globex
Reference mode keeps the invoice smaller and resolves profiles when validating, rendering, or emailing:
ivce new standard 2026-08 --contractor acme --client globex --reference-profiles
That creates invoice fields like:
contractor_ref: acme
client_ref: globex
Profile references are profile names, not paths. Receipt paths may be absolute or relative to the selected workspace.
Emailing With Gmail
Client email settings live in each invoice under client:
client:
name: Globex Corporation
billing_email: accounts@example.com
cc:
- manager@example.com
email_from: you@example.com
Send through Gmail SMTP with a Gmail app password:
export GMAIL_USER="you@example.com"
export GMAIL_APP_PASSWORD="your-app-password"
ivce email workspace/invoices/2026-06.yml
By default, ivce email attaches workspace/dist/YYYY-MM.pdf. Use --pdf or --receipt-bundle to override or add attachments.
For non-default workspaces, pass --workspace to validate, render, and email so referenced profiles, receipts, and default output paths resolve from that workspace.
Privacy and Safety
Invoice data is stored in local YAML files. Generated PDFs, Typst outputs, receipt bundles, and the
default workspace/ directory are intended to stay private and are ignored by this repository.
Email is sent only when ivce email is run without --dry-run. Always validate and render an
invoice before sending it.
Data Model
Currency is a string field, so USD is supported without hardcoding the tool to USD only. Monetary amounts are decimal values and are formatted with two fractional digits.
Due dates are optional. Set due_date directly on an invoice, or set
defaults.payment_terms_days to generate one automatically. If neither is present, the PDF
and default email body omit the due date.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ivce-0.1.0.tar.gz.
File metadata
- Download URL: ivce-0.1.0.tar.gz
- Upload date:
- Size: 26.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adbf172a228bcb1c4f4ef10a967b87f860318d8a891380ccbb1916716fcd6969
|
|
| MD5 |
d728e5ff8a9da2ffd1111d8268ec6c12
|
|
| BLAKE2b-256 |
ac978de009bd61b44c4f23e8d9dadcb726012836a842ac36d8203d72b9425394
|
Provenance
The following attestation bundles were made for ivce-0.1.0.tar.gz:
Publisher:
publish.yml on dmnelson/ivce
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ivce-0.1.0.tar.gz -
Subject digest:
adbf172a228bcb1c4f4ef10a967b87f860318d8a891380ccbb1916716fcd6969 - Sigstore transparency entry: 2009232125
- Sigstore integration time:
-
Permalink:
dmnelson/ivce@1a5ac8b118e84abd8034e9372882a7b2835be8e1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dmnelson
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1a5ac8b118e84abd8034e9372882a7b2835be8e1 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ivce-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ivce-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72c2dc0c3275b7c501bf3118df20a4ae77a719fdd12335bbc9c28c8d0fdb63ae
|
|
| MD5 |
ab52c6db9972a9449fd1e6c6cceb2100
|
|
| BLAKE2b-256 |
c5d9dede022cf689945ac007291eb5c4b1c933a8427075b30d1616a08bfc54b2
|
Provenance
The following attestation bundles were made for ivce-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on dmnelson/ivce
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ivce-0.1.0-py3-none-any.whl -
Subject digest:
72c2dc0c3275b7c501bf3118df20a4ae77a719fdd12335bbc9c28c8d0fdb63ae - Sigstore transparency entry: 2009232209
- Sigstore integration time:
-
Permalink:
dmnelson/ivce@1a5ac8b118e84abd8034e9372882a7b2835be8e1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dmnelson
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1a5ac8b118e84abd8034e9372882a7b2835be8e1 -
Trigger Event:
workflow_dispatch
-
Statement type: