ALdía turns an AI assistant into a business operator you can actually trust with money.
Instead of handing an agent database access, ALdía exposes the business itself — invoicing, payments, customers, vendors, inventory, checks, expenses, cash — as 59 permission-controlled MCP tools, with identity, idempotency, structured errors and an immutable audit trail already built in.
You: "John paid invoice #1842 with this check." [photo attached]
Assistant ── reads it, extracts the data, asks what's missing
↓ MCP
ALdía ── validates, executes, records
│ ✓ payment recorded ✓ check added to the portfolio
│ ✓ customer balance updated ✓ operation audited
↓
Browser ── where you see exactly what happened, and fix it if needed
The assistant interprets. ALdía validates and executes. The web console supervises.
No accounting rule lives inside a model's prompt, and the agent never writes SQL.
Most business software is built around forms. ALdía is built around operations.
An agent connected to ALdía doesn't get a database. It gets a vocabulary:
find_customer find a customer
get_customer_balance what they owe, and since when
create_invoice issue an invoice
record_payment record a customer payment
record_vendor_payment pay a vendor
record_expense record an expense
find_product check inventory
list_checks checks in the portfolio
list_debtors who owes money, and since when
get_audit_log what happened, and who did it
All 59 of them are business actions, not fiscal ones: create_invoice means
the same thing in Miami as in Córdoba. What changes underneath is which rules
the server applies.
Every write goes through the same code path as the web application: the same validations, the same transaction, the same audit record. There is no second implementation to drift out of sync, because the MCP server never touches the database — it speaks HTTP to the same API your browser does.
When an agent starts moving real money, four problems show up. All four are already solved here, and covered by tests.
🔁 Idempotency that actually holds
An agent retries when it doesn't get a response — and a lost response doesn't
mean a lost operation. Send X-Operation-Id and the identifier is reserved
before execution, not recorded after it. Two simultaneous retries can't both
get through. (The naive version — check, execute, then save — leaves a window
where both do. We wrote the test that proves it, then closed it.)
🧠 Errors an agent can act on
Every error carries a stable codigo, the data that filled it ( params), and
an accion from a closed set of four:
{ "detail": "Not enough stock for 'Coca 2.25': 12 requested, 5 on hand",
"codigo": "STOCK_INSUFICIENTE",
"accion": "corregir",
"params": { "producto": "Coca 2.25", "pedido": 12, "disponible": 5 } }
reintentar · corregir · preguntar · abortar. A new agent behaves
correctly without knowing the whole catalogue — it just reads that field. The 32
codes are published at GET /api/errores, no authentication required, because
an agent getting a 401 needs to be able to look it up.
🔐 Who asked, and who executed An agent can declare which person it's acting for. Permissions are the intersection of the service account and that person — never one or the other, so a leaked agent credential can't become a universal impersonation key. Acting on someone's behalf is an explicit permission an administrator grants, account by account.
❓ Ambiguity without redoing the work "There are two customers named John Smith. Which one?" The operation is stored exactly as it was going to run; confirming it means "execute what you already described, with this clarification." The agent doesn't rebuild the request and risk changing something else.
📋 An audit log that can't be edited Every write is recorded automatically by middleware — including the rejected attempts, which are usually the interesting ones. It lives in its own schema, so it survives a full database wipe, and there is no endpoint to delete or modify it. Not even for the administrator.
ALdía is a single Python process and one SQLite file. It installs on the shop's own PC and the terminals reach it over the local network.
It works with the internet down. Nothing is loaded from a CDN — that was a deliberate fix, not an accident. A store that loses connectivity keeps invoicing.
It also backs itself up: once a day at startup, keeping the last 7, using
SQLite's backup API rather than a file copy — in WAL mode, copying the file
silently loses the day's most recent sales. Each copy is verified with
integrity_check on the spot.
Business operations are universal. Tax rules aren't.
ALdía keeps a common engine and swaps country packs. One configuration key changes how identifiers are validated, which tax applies, and whether documents need approval from an agency.
| 🇦🇷 Argentina | 🇺🇸 United States | |
|---|---|---|
| Tax ID | CUIT, with check digit | EIN, format + assigned prefix |
| Sales tax | VAT — closed list of legal rates | Sales tax — any plausible rate |
| Document authorization | CAE from ARCA (WSAA + WSFEv1) | none |
| Currency | ARS | USD |
| Payment methods | cash, check, transfer, cards | + ACH |
| Vendor records | — | legal name, DBA, W-9, 1099 worksheet |
U.S. sales tax is not a compliance solution, and the system says so itself.
It applies one rate you type in, to everything. That's correct for a
single-location business with obligations in one jurisdiction. It does not
determine jurisdiction (state + county + city + special districts), apply
origin/destination sourcing, track economic nexus, handle exempt categories, or
manage resale certificates. A specialised tax provider can be plugged in
without touching the core — the interface is there and tested; no integration
ships with it. GET /api/config/pais returns these limits as advertencias
so an agent can repeat them to the user instead of hiding them.
Adding a country means implementing three questions — how the tax ID validates, what tax applies, whether documents need authorization — and nothing in the core changes. Your agent keeps calling the same tools either way.
Every amount is stored as integer cents, with commercial rounding applied once, explicitly, at the point of conversion. This isn't pedantry:
sum([0.10] * 10) # 0.9999999999999999
1234.56 * 0.21 # 259.25759999999997 ← the VAT on a real invoice
Balances, ledger entries and period totals reconcile to the cent, permanently.
Invoice numbering comes from a sequence table, not max + 1, so voiding a
document never causes its number to be reused.
Requires Python 3.10+. Runs on Windows, Linux and macOS — the server is plain Python and SQLite, with no platform-specific dependencies.
On the machine that will act as the server:
git clone https://github.com/jonalemndi2/ALdia.git
cd ALdia
Linux / macOS
./instalar.sh # creates the venv and installs dependencies
./iniciar_web.sh # starts the server
Windows
instalar.bat
iniciar_web.bat
For a production install, pin the exact verified versions instead of the
compatibility ranges: ./instalar.sh --lock (or, on Windows,
.venv\Scripts\python.exe -m pip install -r backend\requirements.lock.txt).
Then open http://localhost:8000. First login is admin / admin123, and the
system refuses to let you operate until you change it — that password is
published in this file, so an installation that keeps it has a known way in.
To connect an assistant, see mcp/README.md. Give it a
limited-role account, not the administrator's: a connected agent can create
documents and move real money.
Start ALdía first, install the MCP environment as described in
mcp/README.md, and provide ALDIA_USER, ALDIA_PASSWORD and
the optional ALDIA_URL through the client's or operating system's secure
credential mechanism. Never put the password in a command or in the repository.
The examples below use Linux/macOS paths; on Windows use the absolute paths to
mcp\.venv\Scripts\python.exe and mcp\server.py.
claude mcp add aldia -s user -- \
"/path/to/ALdia/mcp/.venv/bin/python" "/path/to/ALdia/mcp/server.py"
claude mcp list
openclaw mcp add aldia \
--command "/path/to/ALdia/mcp/.venv/bin/python" \
--arg "/path/to/ALdia/mcp/server.py"
openclaw mcp probe aldia
hermes mcp add aldia \
--command "/path/to/ALdia/mcp/.venv/bin/python" \
--args "/path/to/ALdia/mcp/server.py"
hermes mcp test aldia
All three clients discover the same 59 tools. For a safe first check, ask the agent to find a customer, read a balance, or show today's cash; require an explicit review before issuing a document or moving money.
HTTPS is mandatory. Without a certificate, credentials and session tokens travel in plaintext. Use a reverse proxy — Caddy handles it in a few lines.
And declare your proxy: ALDIA_PROXIES=127.0.0.1. Without it the server sees
every request as coming from the proxy, and eight failed logins are enough to
lock out the entire store.
- Anyone with filesystem access to
backend/aldia.dbcan edit it outside the application. There, the protection is OS permissions and backups. - The audit log records writes, not reads.
- One installation, one business. There is no multi-tenancy, by design.
- U.S. sales tax: see the warning above.
- No 1099 forms are generated — only a worksheet. Thresholds, exclusions and deadlines change every year, and a return filed wrong is worse than none.
Every public release passes private functional validation before publication. GitHub additionally verifies installation and dependency integrity on Windows, Linux and macOS, and rejects databases, credentials, certificates and test material from the public tree.
| docs/AGENTES.md | What agents can do, and what must not be broken |
| docs/CONVERSATIONAL-COMMERCE.md | Not built yet — an open design for autonomous selling, and where to start |
| docs/INTERNACIONALIZACION.md | How country packs work; what's done and what isn't |
| docs/AFIP.md | Argentine electronic invoicing setup |
| mcp/README.md | Installing and connecting the MCP server |
| skills/ | Task playbooks for the assistant, per country |
| SECURITY.md · CONTRIBUTING.md | Reporting a vulnerability · contributing |
ALdía was designed and written with AI coding assistants, and it is built to be operated by them. Both halves of that sentence are the point.
Written with — Claude Code, OpenAI Codex, Google Gemini, DeepSeek, in Visual Studio Code.
Linux and macOS support update — implemented with
OpenClaw using OpenAI GPT-5.6-sol. This update
added the native instalar.sh and iniciar_web.sh scripts and the automated CI
matrix that verifies ALdía on Linux, macOS and Windows.
Built to be driven by — any MCP client. OpenClaw is the assistant this engine was shaped around, but nothing here depends on it: the 59 tools are plain MCP, and the server never assumes which client is on the other end.
That's deliberate. An engine that only works with one assistant isn't infrastructure — it's a plugin.
Apache License 2.0 — see LICENSE.
Use it, fork it, build a product on it, ship it commercially. No copyleft obligation: you are not required to publish your changes. The license includes an explicit patent grant, which matters for software that computes taxes.
If you build something with it, I'd genuinely like to hear about it.
Built by Jonathan Alemandi (@jonalemndi2).
It started as a replacement for a VB6 + Access system running a real shop in Del Campillo, Córdoba, and turned into an attempt to answer a harder question: what does a business system need before it is safe to let an AI agent operate it with real money?
Most of the interesting decisions here are defensive, and the reasoning behind
them is written into the code rather than lost in a commit message — see
backend/dinero.py on why money is never a float,
backend/database.py on why writes take the lock up
front, or backend/idempotencia.py on why checking
before writing leaves a hole big enough to bill someone twice.
Issues and pull requests welcome.