TaxHacker: The Self-Hosted Accounting App That Lets You Rewrite the Brain

A deep dive into the receipt parser that turns PDFs, photos, and invoices into structured transactions, with user-defined prompts, dynamic schemas, and local-model support.

8 to 10 min read View on GitHub More from nlnu499

A wide workshop scene where scattered receipts, invoices, and paper clutter on the left are being pulled into a clean ledger on the right by a visible control lever in the middle. The image explains that TaxHacker turns messy financial documents into structured accounting data while letting the user steer the extraction logic.
TaxHacker sits between chaos and bookkeeping. The user does not just upload documents. They shape the logic that turns them into transactions.

In short, it's a self-hosted parser/organizer for invoices, receipts and other financial documents, which saves me a lot of time and nerves as a freelance coder and indie hacker.

vas3k, Creator · r/selfhosted TaxHacker post
Key Takeaways

Most receipt tools try to make extraction invisible. TaxHacker does the opposite. It exposes the brain, then lets you tune it.

The Brain Is Programmable

The project’s core move is simple to describe and unusual in practice. Instead of asking a model to "read a receipt" and hoping for the best, TaxHacker builds the extraction task from user-defined fields, categories, and prompt logic, then constrains the model with a dynamic schema. That means the output is not just text. It is shaped to fit the ledger.

TaxHacker’s pipeline is less like document OCR and more like a compiler. User rules become schema, schema constrains the model, and the model output becomes typed accounting data.

That distinction matters. A normal extraction tool produces a best-effort guess. TaxHacker tries to produce a valid object. The difference is the difference between a helpful demo and a system you can trust with your books.

Why This Exists

A hedcut-style portrait of vas3k rendered in black ink on white. The portrait is meant to show the creator behind TaxHacker and connect the project to its real-world tax frustrations and self-hosted philosophy.

That origin story is not cosmetic. The app comes from real tax friction, especially the kind that freelancers feel when receipts, invoices, foreign payments, and privacy concerns all land in the same pile. TaxHacker is built for people who want automation without handing their records to a black box.

From Paper Chaos to Typed Transactions

The pipeline starts with an unsorted inbox. Uploads land there first, then the app analyzes the document, validates extracted data against the schema, and only then turns it into a transaction. The item splitter is the most practical twist. A single invoice can become several accounting entries when one receipt mixes business and personal purchases.

A close-up of a receipt being torn into structured fragments that feed into a small ledger grid. One fragment becomes a client meal, another becomes software, and another is marked personal. The image explains how TaxHacker splits one document into multiple typed accounting entries.
TaxHacker is built for messy receipts, not clean ones. The item splitter makes one invoice behave like several accounting decisions.

That is where the app stops behaving like an archive and starts behaving like a workflow. It is not preserving documents for later. It is deciding what each line means now.

Prompt to transaction

The Other Clever Trick: Currency as a First-Class Problem

TaxHacker treats foreign money as part of the accounting problem, not a separate cleanup step. The app includes historical exchange-rate lookup, so the transaction can be converted using the rate from the document date instead of a generic current-day estimate. That makes the output more useful for tax work, especially when the document trail crosses borders.

// Conceptual shape of the currency step
const converted = await getHistoricalRate({
  from: receipt.currency,
  to: userBaseCurrency,
  date: receipt.date,
})

const amountInBase = receipt.amount * converted.rate

saveTransaction({
  ...receipt,
  amountInBase,
  exchangeRate: converted.rate,
})
ProblemGeneric receipt appTaxHacker
Foreign-currency receiptStores the amount, leaves conversion to the userLooks up a historical rate and stores the converted value
Mixed-item invoiceKeeps one document as one recordCan split a receipt into multiple accounting entries
Tax relevanceGood for storageBuilt for deductible, typed financial workflows

That same philosophy shows up in the built-in invoice generator. It is a small signal, but a telling one. The product is not trying to be a single-purpose parser. It is trying to be the place where a freelancer’s financial paperwork actually gets finished.

Why Local Models Matter Here

The multi-provider layer is not just a convenience feature. It is what makes the privacy story credible. TaxHacker can route requests to OpenAI, Gemini, Mistral, or an OpenAI-compatible local endpoint such as Ollama or LM Studio. In practice, that means the same pipeline can run as cloud-assisted, self-hosted, or somewhere in between.

Provider modeWhat it buys youWhat it asks of you
Cloud modelConvenience and strong general extractionYou send financial data to a third party
Local OpenAI-compatible modelPrivate inference and local controlYou manage setup, performance, and quality
Pluggable provider layerFlexibility across environmentsYou accept another abstraction layer to maintain

This is where TaxHacker becomes more than a privacy pitch. The privacy claim is enforced by the architecture. If the model endpoint is replaceable, the data path is replaceable too.

How It Stacks Up

ProjectBest atAI extraction depthAccounting focusFit for TaxHacker-like workflows
Paperless-ngxDocument archiving and OCRLight or community-addedNot primarily accountingStrong on storage, weaker on structured tax output
Firefly IIIPersonal finance and bookkeepingNot AI-firstManual bookkeeping and budgetingStrong on finance, weaker on receipt automation
Receipt WranglerSelf-hosted receipt managementAI-assistedReceipt workflows with collaborationClosest in spirit, but narrower in accounting specificity
TaxHackerAI-steered accounting intakeCore featureStructured tax-ready transactionsBuilt for the exact receipt-to-ledger problem

The category line is the real story. Paperless-ngx is a document archive. Firefly III is a finance system. Receipt Wrangler is a modern receipt manager. TaxHacker lives where those tools overlap, then adds user-steerable AI as the core mechanism rather than an add-on.

The Trade-Offs

Flexibility cuts both ways. A system that lets users rewrite prompts, fields, and categories can adapt to real tax workflows, but it also becomes easier to break. Prompt drift, schema mismatch, and multi-tenant safety all become live product questions, not theoretical ones.

The main idea that differentiates TaxHacker from other similar AI-parsers is that I wanted to make a tool that gives the user 100% control over all aspects: Data privacy - my documents are stored on my home server and accessible as simple files even if the app is dead, no proprietary formats. Unlimited structure - I didn't want to be limited to my predefined database structure once and forever, I wanted to be able to create any new columns, categories and fields at any time (like good old Excel). Fully customizable LLM prompts - even the main system prompt can be changed in two clicks in the settings if I don't like it.

vas3k, Creator · r/selfhosted TaxHacker post

That quote reads like a product brief and a philosophy statement at once. The bet is clear: give users enough control and they can encode their own accounting reality better than a fixed-purpose app can.

What TaxHacker Suggests About the Future

TaxHacker is a good example of where AI-native utilities are heading when they are built for real work instead of chat. The point is not that the model is intelligent. The point is that the software lets the user author the intelligence. That is a sharper idea than automation alone, and a more durable one than novelty.