CapyInn: Building an Offline-First Hotel PMS as a Solo Builder
A real hotel, a solo builder, and a disciplined AI-agent workflow — from paper logbook to production software.
Case study · July 2026

At a glance
- What: CapyInn — an offline-first desktop property management system (PMS) for a 10-room mini hotel in Vietnam.
- My role: Solo product builder. I scoped the product, wrote the specs, and set the guardrails; AI coding agents wrote most of the code under a spec-and-verify discipline.
- Stack: Tauri 2 · Rust · React 19 · TypeScript · SQLite.
- AI inside the product: an on-device receptionist agent — a Gemma model I fine-tuned for front-desk work, running fully offline. Read how the dataset and fine-tune were built →
- Status: Open source (MIT), running the hotel's front desk every day.
- Timeline: First code in early 2026; open-sourced in April; in daily operation by mid-2026.
- Code: github.com/chuanman2707/CapyInn
Context
The hotel is a mini hotel in Vietnam: ten rooms across five floors, two rooms per floor, a small team, and a front desk that ran entirely on paper.
Here is what checking in one guest used to look like. The guest hands over their CCCD (the Vietnamese national ID card). Someone at the desk copies the name, ID number, date of birth, and address into a logbook by hand. Then they retype the same details into the government's residence-declaration website, because every overnight guest in Vietnam must be reported. At checkout, the nightly bill is calculated by hand — base rate, extra hours, drinks from the fridge. At the end of the day, someone reconciles the cash drawer against the logbook and hopes the numbers agree.
That's roughly five minutes per guest, most of it retyping information that already exists on a plastic card, plus money math done under time pressure with real consequences when it's wrong.
Off-the-shelf cloud PMS products exist, but they are built for bigger properties: subscription pricing, a hard dependency on the internet connection, feature lists three times longer than a ten-room hotel needs, and the hotel's data living on someone else's server.
I build products for a living, and this time the user was someone I see every day. So I decided to build the tool myself — and to treat it as a real product, not a weekend script. This case study is about what I built, and just as much about how a single person shipped it.
Problem & constraints
The problems were plain to see at the front desk:
- Guest intake was slow. About five minutes per guest, dominated by copying ID details twice — once into the logbook, once into the government website.
- Information was fragmented. Room status lived in people's heads, bookings in the logbook, money in a drawer. Answering "which rooms are free tonight?" meant asking around.
- End-of-day was manual and fragile. Reconciling revenue by hand, every night, with no audit trail when something didn't add up.
The constraints shaped the solution more than the feature list did:
- It must work fully offline. The front desk cannot stop working because the internet did. No cloud backend, no subscription, and the hotel's guest data stays on the hotel's own machine.
- One person builds it. I had no team, which meant scoping ruthlessly and automating quality control instead of relying on code review by colleagues.
- The money must never be wrong. A PMS is a financial system wearing a hospitality costume. Billing mistakes cost real trust with real guests.
- The end user is not technical. Setup has to be guided, and the daily flows have to be obvious — one click where one click is possible.
That first constraint deserves a word, because it was the one decision people actively argued against. When I started, the advice I got was that a PMS has to be online: if a guest books over the internet at midnight while the front-desk machine is off, you sell the same room twice. That's true — and it's why most PMS products on the market are cloud-first. It's also true only at a certain scale.
I've managed this hotel for ten years. In that time I've been overbooked exactly twice, and both times the fix took five minutes: walk over to the neighboring hotel and book the guest a room there. For a ten-room property running mostly on walk-ins, the overbooking risk that justifies a cloud architecture rounds to zero — while the costs of that architecture (a subscription, an internet dependency at the front desk, guest data on someone else's server) would be paid every single day. I built for the risk profile this hotel actually has, not the one enterprise software assumes.
What I built
CapyInn is a desktop app that runs the entire front-desk operation locally:
- Onboarding that generates room types, the floor layout, and operating defaults, so a new property is usable in minutes rather than after a setup project.
- A live room map — who's in which room, what's clean, what's due out.
- Check-in, check-out, and extend-stay flows with nightly pricing computed automatically.
- Reservations alongside walk-ins.
- A folio per stay — every charge and payment in one auditable place.
- Housekeeping status, expenses, and an analytics dashboard.
- Night audit — the end-of-day reconciliation, built in instead of done by hand.
- Automatic local backups with a retention policy, in-app failure alerts, and a weekly restore drill, because a local-first app carries local-first responsibility for the data.
- Auto-update, so shipping a fix doesn't require touching the front-desk machine.


The OCR pipeline
The single biggest time sink was retyping ID cards, so that's where the app earns its keep. The desk scans the guest's CCCD on a flatbed scanner, which drops the image into a folder. CapyInn watches that folder: a new scan triggers OCR automatically, extracts the full name, ID number, date of birth, and address, and pops up a pre-filled guest card. The receptionist assigns a room, and one button copies the guest's details in exactly the format the government residence-declaration site expects — retyping eliminated at both ends.


The OCR runs on ocr-rs, a Rust library built on PaddleOCR, rather than the more common Tesseract. PaddleOCR handles Vietnamese text and ID-card layouts far better, it's pure Rust so it ships inside the app with no external runtime, and it uses Metal GPU acceleration on macOS.
The AI receptionist
CapyInn also ships with its own AI: a receptionist agent that runs entirely on the front-desk machine. I fine-tuned it from Google's Gemma (the E2B instruction-tuned variant) specifically for hotel front-desk work, and published the model on Hugging Face. It answers operational questions in Vietnamese — which rooms are free tonight, what the rate is for an extended stay, how to handle a late checkout — and it can suggest PMS actions, reaching the app's data and tools through a built-in MCP gateway.
The word suggest is doing deliberate work in that sentence. The agent has no write access to anything. When it proposes a check-in or an extension, that proposal goes through the same validated, audited command boundary as a human click. A small local model will sometimes be wrong; the system is designed so that being wrong is cheap.
Like everything else in CapyInn, it works with the internet cable unplugged — no API keys, no per-token bills, and guest data never leaves the machine.
Architecture decisions
Three decisions defined the technical shape. Tauri over Electron: the whole app is about 25 MB — 15 MB of which is OCR models — because Tauri uses the OS's native webview and a Rust backend instead of bundling Chromium. SQLite as the single source of truth: one local file, transactional, trivially backed up. An explicit command boundary: nothing in the app writes to the database directly — every business action is a named, validated command. That last decision wasn't just architectural taste. It exists because of how this app was built.
How I built it: the AI-agent process
Most of CapyInn's code was written by AI coding agents. I'm not going to hedge that, because the interesting part isn't the confession — it's the system that made it safe.
My actual job was direction, constraints, and verification. The build ran on a loop: spec → plan → implement → verify. Every feature started as a written design document — the repo carries 50+ dated design specs, from checkout settlement to backup retention to crash logging — produced by a structured brainstorming session where the agent interviewed me about requirements before any code existed. Each spec became a task-by-task plan, agents executed the tasks, and nothing counted as done until it passed the verification suite.
The second ingredient is a rulebook. The repo has a set of PMS safety rules written the way you'd write them for a junior team, except the audience is AI agents. A sample:
- Financial amounts must use integer minor units, never floats.
- Ledger and folio financial records must be append-only; corrections require reversal or adjustment rows.
- Retryable commands must be idempotent: same key + same payload replays the prior result.
- Agent memory is not PMS truth; LLMs may suggest commands, but PMS state changes only through validated, authorized, audited commands.
This is why the command boundary exists: when your programmers are stochastic, you don't let anyone — human, UI, or agent — mutate the database freely. Every write is a command with an actor, an idempotency key, and an audit trail. And notice that the rules constrain two different AIs: the coding agents that built the system, and the receptionist agent that now lives inside it. One set of guardrails covers both.
The third ingredient is gates instead of line-by-line supervision. A no-float-money script fails the build if any money value touches floating point. Replay tests prove idempotency actually holds. Repeat runs catch flaky behavior before it reaches the front desk. I don't read every line the agents write — I make the rules executable and let the suite say no.
That's the thesis of the whole project: AI agents give you speed, but discipline — specs before code, rules as tooling, verification as a gate — is what turns that speed into production software.
Results
CapyInn runs the hotel's front desk every day. The measured result on the metric that mattered most: guest processing went from about five minutes to about sixty seconds — scan the ID, confirm the popup, assign the room, copy the declaration.

Night audit went from a manual end-of-day ritual to a built-in step, with every charge traceable to a folio and every folio to a command in the audit trail. Room status, bookings, and money now live in one place, on the hotel's own machine, with automatic backups and a weekly restore drill guarding the data. The fine-tuned receptionist agent answers front-desk questions on that same machine, fully offline.
The project is open source under the MIT license, with 250 commits on the public repo and CI running the verification suite on every change. And because the user sits at a front desk I can walk to, the feedback loop is brutal and honest: if a flow is confusing, I hear about it the same day.
What I learned
- Specs before code beat fixes after. The half hour spent answering an agent's questions about edge cases is the cheapest debugging I've ever done.
- Hard constraints simplify. Offline-first sounded limiting; it actually deleted whole categories of work — auth, sync, hosting — and made the architecture obvious.
- AI agents need guardrails, not babysitting. Reviewing every generated line doesn't scale for one person. Encoding the rules as executable checks does.
- Build for a user you can watch. Ten rooms and one front desk taught me more about product than any dashboard of anonymous users ever has.
The code is at github.com/chuanman2707/CapyInn. If you're building something similar — a local-first tool for a real business, or a serious product with AI agents doing the typing — I'd genuinely enjoy comparing notes. Reach me at hello@longtrinh.com or on LinkedIn.