DEV Community

Daniel Pertu
Daniel Pertu

Posted on

Our README tells you to make a Gmail app password, and nothing in the app has read one for months

Notifio is a desktop app that watches rental listing searches and tells you when something new appears. The repository has one README, in app/, and git log on it is two lines long:

bf3824b  Add desktop notifications and live per-search monitoring state   2026-09-22
e7f10b2  first commit                                                     2026-07-20
Enter fullscreen mode Exit fullscreen mode

Two commits, two months apart. That second commit changed 82 lines and deleted 25, and reading the diff is instructive, because of what it chose to fix.

It rewrote the feature list:

- **Automated monitoring**, which checks your saved searches every ~30 seconds
- **Desktop alerts** the moment a listing is found, ahead of the email
- **Email alerts**, grouped by site, sent from the Notifio server
Enter fullscreen mode Exit fullscreen mode

The first of those three lines had said "polls your saved searches every ~30 seconds", with a dash where the comma now is. The second and third are new. So part of that commit is information, and part of it is punctuation.

The punctuation is a house rule: no long dashes in anything a user reads. I wrote about how far that rule had to reach in Six places a copy rule has to reach, and not one of them is a page. The sweep walked through this file line by line, replacing dashes with commas, in the feature list, the setup steps and the tray menu.

It walked past every factual error on the way.

Line 1

# Room Monitor
Enter fullscreen mode Exit fullscreen mode

That is the first line of the README for an app called Notifio. The name changed, the domain was bought, the installer was renamed, the structured data on the website declares a SoftwareApplication called Notifio, and the README still carries the working title from July.

The email instructions describe an architecture that was removed

2. **Configure email alerts**:
   - Create a `.env` file in the app's installation directory (copy `.env.example`)
   - Set `GMAIL_USER` to your Gmail address
   - Set `GMAIL_APP_PASSWORD` to a Gmail App Password ([create one here](...))
Enter fullscreen mode Exit fullscreen mode

This is the only part that would actively cost a reader time, because it is a real, followable instruction. You would go to your Google account, turn on two-factor authentication if you had not, generate a sixteen-character app password, and paste it into a file.

Nothing would read it. Here is the whole of the current .env.example:

# Notifio server URL (where your Next.js server is deployed)
NOTIFIO_SERVER_URL=https://notifio.app

# Optional: port for the embedded web UI (default: 3000)
# PORT=3000
Enter fullscreen mode Exit fullscreen mode

There is no GMAIL_USER to set, because the app has not sent an email itself in a long time. It posts to the server instead:

const res = await fetch(`${serverUrl()}/api/notify`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: auth.email, token: auth.token, type: 'reply', reply: { ... } }),
  signal: AbortSignal.timeout(15_000),
});
Enter fullscreen mode Exit fullscreen mode

The server owns sending, templating and the licence check, and the desktop app holds no mail credentials at all. That is a better design for several reasons that are not this post's subject: one place to fix a broken template, one sender reputation to maintain, and nothing resembling a password sitting in a text file in a user's home directory. It is also two months old, and the README is older.

The troubleshooting section is downstream of the same rot:

### No email received
- Check `.env` file exists and has correct credentials
- Test Gmail credentials with: `node test-email.js`
Enter fullscreen mode Exit fullscreen mode

node test-email.js is a command you can type. There is no test-email.js in the repository. There has not been one for as long as the file has existed in its current form.

Three more that are not even arguable

1. Download `Room Monitor Setup 1.0.0.exe` from the `dist/` folder
Enter fullscreen mode Exit fullscreen mode

There is no dist/. Installers are written to release/, and they are named notifio-setup.exe, notifio-arm64.dmg and notifio-x64.dmg, because those exact names are the keys the download endpoint fetches from object storage. The version is 1.1.0.

The monitor polls every ~30 seconds with ±5s randomization. To change this, edit `monitor.js`:

const delay = randomDelay(30000, 5000); // 30s base, ±5s jitter
Enter fullscreen mode Exit fullscreen mode

The file is monitor.ts. The repository has been TypeScript since the first commit; monitor.js only ever existed in the project layout block that the same September commit replaced, further down the same file.

# Install dependencies
npm install
Enter fullscreen mode Exit fullscreen mode

The app is pnpm-only, and not by accident. The installer's file list excludes 25 specific paths under node_modules/.pnpm/, which is where pnpm keeps packages and npm does not. I wrote about that list in Nine include globs, thirty-three excludes, and twenty-five of them name a pnpm store path. Following the README's own install instruction produces a node_modules layout in which every one of those exclusions matches nothing, so the next build quietly ships the TypeScript compiler, Vite, esbuild, Rollup, Tailwind and electron-builder to users.

Why this one rotted and the others did not

It would be comfortable to say the README rotted because documentation always rots. I do not think that is the reason, because other documentation in this project did not.

The public help page is current. The per-site pages are current, and there is a test that fails if any of them is unreachable from the site. The FAQ is a TypeScript array that also emits the FAQPage structured data, so a wrong answer there is wrong in Google's index, which is a consequence I notice.

This file has none of that. Look at the exclusion list from the packaging post again:

"!**/README*"
Enter fullscreen mode Exit fullscreen mode

The README is not in the shipped app. It cannot be: it is excluded by name, along with changelogs and licences, to keep the bundle small. So no user has ever opened it. The real first-run instructions are on the download page and the help page, and those get read, which is why they are right.

The audience for app/README.md is one person with a clone of the repository, and that person already knows the app is called Notifio. A document with an audience of one and no failure mode is a document with no feedback loop, and no amount of good intent substitutes for one.

The repair, and the part of it that is not writing

The fixes are obvious: rename the heading, delete the Gmail section, delete the test-email.js line, point the polling note at monitor.ts, change npm to pnpm, change dist/ to release/, correct the artifact names.

The part that is not writing is making it fail. Two options, and they are not equivalent:

  1. Test the claims. The server side already does this for pages, with four test files and no framework, run by node --test. A README is harder, but the mechanical claims are not: a test can assert that every path, filename and script name mentioned in the README exists.
  2. Delete the stale half. A short accurate README beats a long one with a two-month-old product name in it. Everything about first-run setup belongs on the help page anyway, where a reader can actually find it, and where being wrong is visible.

I am going to do both, in that order, because option 2 without option 1 just resets the clock.

The general version of this, for anyone with a repository older than a few months: open your README and check the first line. Not the install steps, not the architecture diagram. The name.

Top comments (0)