← Work

Work / App Prototype

DwellOS: one local file for a rental apartment

DwellOS is a browser app that keeps one rental apartment's leases, costs, tax categories, documents, repairs and tradespeople in a single local file. It flags likely duplicate invoices, and an optional AI Intake step drafts records from a dropped invoice for me to check before anything is saved.

Demonstration data. Invented data.

I type a supplier, an invoice number and an amount, press Save, and DwellOS tells me I have already entered that invoice. That one check is the point of the app: leases, invoices, repairs and tax categories in one place, so a year’s costs are already sorted when the tax return is due.

The DwellOS dashboard on invented data: four summary tiles, an AI Document Intake panel, a tax working summary, recent costs and open issues
Figure 1. The dashboard, shown in the app’s demo mode with an invented apartment. Four summary tiles, an AI Document Intake panel, the tax working summary, recent costs and open issues sit on one screen.

At a glance

  • Status: Prototype. It tracks one apartment.
  • Platform: a web page you open from disk. There is no server and no build step.
  • Stack: plain JavaScript, HTML and CSS, with the browser’s local storage holding the data.
  • Built with: Claude Code and Codex.
  • AI inside the product: optional. AI Intake sends a dropped document to the OpenAI API and gets back a draft record. Everything else is ordinary code.

The duplicate check in action

Video 1. A 38-second walkthrough on invented data. I open Costs & Tax, add a second copy of an existing invoice, see it flagged, then look at the duplicate check and tell DwellOS that one flagged pair is not a duplicate. The last few seconds tour leases, tradespeople and the AI Intake screen. Watch how the flag appears the moment the second copy is saved.
Text version of the video
  1. The dashboard for an invented apartment, with the demo banner showing.
  2. Costs & Tax: thirteen invented costs. One management fee is flagged as a possible duplicate of another with the same supplier and amount.
  3. I add a cost with supplier Harbour Plumbing Ltd, invoice number HP-3391 and amount 185, which an existing record already has.
  4. The new record is flagged. Further down, the Duplicate Invoice Check card lists each match with the reason, and each has a Not duplicate button. I press one.
  5. Leases & Tenants, Tradespeople and the AI Intake screen, which opens ready for a dropped file.

Owning an apartment that someone else lives in produces paper in several places. The lease is in one folder, invoices arrive by email or as a photo of a receipt, a plumber’s number lives in a text thread, and every cost eventually has to be sorted into the categories a tax return wants. DwellOS keeps all of it in one place.

Ten views for one apartment

DwellOS has ten views: a dashboard, AI Intake, the apartment’s permanent facts (meter numbers, energy rating, management company, insurance), leases and tenants, costs and tax, invoices and documents, issues and work done, tradespeople, a history timeline and a place for questions I keep having to look up.

The Costs and Tax view: invented costs with invoice numbers, tax treatment tags, a Form 11 area and two possible-duplicate flags
Figure 2. Costs & Tax, with invented data. Each cost carries a category, a tax treatment (a rental expense, a capital item, private, or needs review) and a Form 11 area, which is the Irish self-assessment return. The red tags are the duplicate check.

The tax fields are working papers, not advice: the app says to confirm treatment before filing. A cost I am unsure about can be marked Needs review, which is an option in its own right rather than a guess made at data entry.

The Tradespeople view: four invented contractors with trade, phone number and a rating from Excellent to Use with caution
Figure 3. Tradespeople. Each contractor has a rating, so “who fixed it last time, and were they any good” has an answer. The names and phone numbers are invented.

Documents are indexed by where the file lives, not stored inside the app. The user guide suggests keeping the PDFs in ordinary folders, with the app holding the pointer.

Catching duplicate invoices

The same invoice reaches me twice easily: once by email, once as a photo of the paper copy. The check flags two records when the invoice number and the amount both match, or when the supplier and the amount both match. The amount must always match, because a supplier appearing twice is normal and a supplier appearing twice with the same amount is worth a look.

Build decision. The check flags and a person decides. Each flag has a Not duplicate button, and the answer is saved against that pair so it is not raised again. In the demo data, a quarterly management fee of the same amount is flagged against the previous quarter, which is exactly the case the button exists for.

Keeping the data on my own machine

I wanted the operating file for my apartment to sit on my own machine, not in someone’s subscription. So the whole thing runs in one page, saves to the browser’s local storage after every change, and uses a JSON export and import as the backup and the way to move between browsers.

AI Intake: a draft, not a record

Typing every invoice in is the dull part. AI Intake takes a dropped PDF, receipt photo, screenshot, text file or .eml email and asks the OpenAI API for one draft: a cost, a document entry and any tradesperson details. The model’s default name in the settings box is gpt-4.1. The request uses a strict JSON schema, so the reply has to fit the fields, with a fixed list of tax treatments that includes Needs review. The system prompt asks for conservative tax classifications and tells the model not to invent missing details. That is an instruction, not a guarantee.

The AI Intake screen: a drop zone, an AI Settings box with an empty key field, and an empty Review Draft Records panel
Figure 4. The AI Intake screen as it opens: a drop zone for an invoice, receipt or email, the AI settings, and an empty Review Draft Records panel where the draft will appear for checking.

The reply does not become records. It appears on a review screen as editable fields, with duplicate warnings, and nothing is saved until I press Create records. On saving, the app also merges a tradesperson into an existing entry when the email, phone number or name matches, and adds a history entry saying the record came from AI.

Under the hood

I built DwellOS with Claude Code and Codex as a single-page JavaScript application: about 1,500 lines in one file, plus a page and a stylesheet. The duplicate rules and the choice to keep everything local are the design at its core.

LayerWhat I used
InterfaceOne HTML page with ten views, plain CSS
Language and runtimePlain JavaScript, about 1,500 lines in one file, running in the browser from disk
BackendNone: no server and no build step
DataOne state object saved to the browser’s local storage after every change, with JSON export and import as backup
IntegrationsOptional: the OpenAI Responses API for AI Intake
Runtime AIOpenAI (default model name gpt-4.1 in settings) for draft records only, behind a review screen
HostingNone: opened from disk
Runtime environmentAny modern browser, opened from a local file
Diagram: one browser page holds ten views and a state object saved to local storage with JSON export and import; the optional AI Intake path goes from a dropped file to the OpenAI Responses API to a review screen to saved records
Figure 5. The data flow, drawn from the code. The dashed boxes are the optional AI path.

What it shows

A useful record keeper does not need a server. One file of plain JavaScript, a state object in local storage and a JSON backup hold an apartment’s leases, costs, documents and tradespeople, and the one check I wanted, duplicate invoices, is a few lines of rules with a person making the final call. DwellOS shows how far a single local file can go for a real-world admin job: an apartment’s paperwork sorted for tax as it arrives, with AI doing the typing and a person making each decision.