Open-source project
zoidsh/meru avatar
zoidsh/meru

Meru: a Gmail desktop client that keeps two accounts in two windows, and a build pipeline with four signing environments

:postbox: Gmail desktop app for macOS, Windows & Linux (formerly Gmail Desktop)

1,040 stars107 forksTypeScriptAGPL-3.0

At a glance

What is it?
Meru, formerly Gmail Desktop, is an Electron app that puts Gmail in a native window on macOS, Windows and Linux, written in TypeScript with a Bun monorepo and shipped by electron-builder. The repository is also a good case study in release engineering, with separate environment files for end-to-end tests, licence keys, code signing and trials, and a build that notarises the macOS artefact.
Who is it for?
Meru is worth adopting for anyone who lives in Gmail and wants it out of the browser tab, because the multi-account window model and the native integrations are the point, and the build system is set up well enough that a fork can produce signed, notarised builds for three platforms.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A browser tab becomes a window, and the name changed with it

Meru, formerly Gmail Desktop, is described as a Gmail desktop app for macOS, Windows and Linux, and the pitch is stated in the header of the README. Tired of losing your inbox in browser tabs? Meru brings Gmail to your fingertips as a desktop app.

The screenshot caption in the README describes two Meru windows, one light and one dark, each showing a Gmail inbox with tabs for a Personal and a Work account. That is the feature the app is built around. The problem being solved is not that Gmail is hard to use, it is that a browser tab is a poor container for a mailbox you check all day, and that two mail accounts competing for the same tab strip is a specific annoyance.

So the design is a native window per account, with light and dark appearances, and the project topics list app, electron, email, gmail, gmail-desktop, linux, macos, ubuntu and windows. The stack is TypeScript on Electron, and the primary language in the repository is TypeScript.

The rename is worth noting because it changes what the project is. Gmail Desktop was a name that said which service it wrapped, and Meru is a name that says nothing about the service, which is the direction a project takes when it wants to be more than a front end for one provider. The README does not say that a second provider is supported, and nothing in the visible documentation claims one, so the rename is currently a statement of intent rather than a description of features.

The project is AGPL-3.0 licensed, the homepage is meru.so, and the last push was on 2026-10-15. The releases are v3.64.0-beta.4, v3.64.0-beta.3 and v3.64.0-beta.2 on consecutive days in mid October 2026, so the current line is a beta that is being cut daily. The maintainer listed is Tim Cheung, and Mark Skelton is listed as former, with a contributors section for the rest of the work.

The build matrix is four platforms and two signing systems

The package manifest is where this project stops being a small Electron wrapper and becomes a release engineering exercise, and the build scripts are the clearest part of it.

The manifest declares the package as meru at version 3.63.2, marked private, with the main entry point at build-js/app.js and a workspaces field of packages/*, so the repository is a Bun monorepo. The scripts are the interesting part:

json
"build:linux": "bun run build:js && bun run build:clean-dist && electron-builder --linux",
"build:mac": "bun run scripts/signing-env.ts mac && bun run build:js && bun run build:clean-dist && electron-builder --mac",
"build:mac:dmg": "bun run scripts/signing-env.ts mac && bun run build:js && bun run build:clean-dist && electron-builder --mac dmg --arm64 --config.mac.notarize=false --config.mac.timestamp=none --config.dmg.writeUpdateInfo=false",
"build:win": "bun run build:js && bun run build:clean-dist && bun run scripts/build-win.ts"

Each platform has its own path, and the macOS one is the most involved. It runs a signing-env script first, then builds the JavaScript, cleans the dist directory, and calls electron-builder. The dmg variant adds four overrides: it targets arm64 only, and it disables notarization, the timestamp and the update info written into the dmg.

Those four overrides are the most informative line in the manifest, because each one turns off something that is normally on. Disabling notarization means the macOS artefact is signed but not submitted to Apple's notary service, and disabling writeUpdateInfo means the dmg does not carry the auto-update metadata. So the dmg target is the unsigned-faster path, presumably for a build that is distributed some other way than a normal release, and the distinction between build:mac and build:mac:dmg is exactly that.

The Windows path is different again, going through a build-win.ts script rather than calling electron-builder directly, and the dev script is bun run scripts/build.ts --dev.

The tooling choices are modern and mostly non-Google. The formatter is oxfmt with a matching oxfmt.config.ts, the linter is oxlint with oxlint.config.ts, hooks are managed by lefthook.yml, tool versions are pinned in mise.toml, and there is a bunfig.toml alongside bun.lock. The type check runs tsc and then a filtered types command across the workspaces.

Four environment files, and they reveal a licence tier

The repository root holds five environment files, and the naming convention of four of them is unusual:.env.e2e.op,.env.license.op,.env.signing.op and.env.trial.op, plus a plain.env.example.

The.env.example file says explicitly that all its values are optional and that you copy what you need into.env, which Bun loads for every command and git ignores. So the.op files are the working copies of the sensitive environments, kept out of git, and the example file is the safe template.

What is in.env.example is where the project's commercial structure becomes visible. There is a block for a signed, notarised macOS build with all seven values or none: CSC_LINK, CSC_KEY_PASSWORD, APPLE_API_KEY, APPLE_API_KEY_ID, APPLE_API_ISSUER, APPLE_TEAM_ID and APPLE_PROVISIONING_PROFILE, with the comment that APPLE_API_KEY is the App Store Connect API key given either as the.p8 file's contents or as a path to it.

Then a block for a signed Windows build through Azure Artifact Signing, again all three or none: AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET. So the Windows artefacts are signed through a cloud signing service rather than with a local certificate, which is the normal way to sign without a hardware token, and the CI environment is what supplies those three values.

And then the two that concern the application rather than the build. MERU_TEST_LICENSE_KEY is described as the end-to-end suite's Pro licence key, without which the Pro tests fail. MERU_TEST_ACCOUNT_EMAIL and MERU_TEST_PROFILE_DIR describe the account signed in to the end-to-end profile and that profile's directory, and the comment says that without both, the tests that need them skip.

So the project has a Pro tier, and it is tested as a separate mode. The.env.trial.op file implies a trial flow exists, though what the trial does is not described in the README, and the existence of.env.license.op as its own environment means licence validation is a distinct configuration from signing and from the test account. None of the mechanism is documented in prose, so for a reader the honest summary is that the app has paid and free modes and the build system treats them as separate test surfaces.

Electron with a preload, typed IPC and a React front end

The devDependencies list in the manifest shows what the application is built from, and the electron-toolkit packages are the most informative entries.

There is @electron-toolkit/preload at 3.0.2, @electron-toolkit/typed-ipc at 1.0.2 and @electron-toolkit/utils at 4.0.0. The preload package is the standard structure for an Electron app that wants a context-isolated renderer, and the typed-ipc package is what gives the main process and the renderer a typed message channel, so the two sides of the window boundary agree on the shape of the messages they exchange.

The front end is React, with @base-ui/react at 1.4.0 and the @dnd-kit family of packages at 0.5.0 for drag and drop, which is how a mail list or a tab strip is reordered. There is @fontsource-variable for the variable fonts, which is how one file can cover a range of weights, and the two appearances in the screenshot are a design decision rather than an accident of a system theme.

The rest of the root tells you the shape of the project. There is a packages/ directory for the monorepo workspaces, a scripts/ directory holding the build and signing scripts, a build/ directory, static/ for assets, media/ for the logo and screenshot, tests/ for the test suites, and patches/ which is the standard place to carry modifications to dependencies. There is a playwright.config.ts, so the end-to-end suite is Playwright driven, and a.env.e2e.op file for its credentials.

The postinstall script runs electron-builder install-app-deps, which rebuilds native modules against the Electron ABI, the standard step for an Electron project that depends on anything compiled. And the extensions:download script, bun run scripts/download-extensions.ts, tells you the app pulls in browser extensions at build time, which is a sensible way to handle a dependency that is not a package registry entry.

The main entry point being build-js/app.js is worth noting, since the JavaScript is built into the build-js directory before packaging, and the clean-dist step exists because electron-builder and the build output share the dist directory.

The security posture is visible in SECURITY.md and the disclaimer

Two things in the repository speak to how seriously the project treats the fact that it holds a live account session.

The first is the disclaimer at the end of the README, which is one sentence: Meru is a third-party app and not affiliated with Google. That is a legal positioning statement, and it is the minimum required for an application that logs into somebody's Google account and displays their mail.

The second is that the repository root contains a SECURITY.md, which is where a project documents how to report a vulnerability. For an app whose whole function is to hold an authenticated session to a mailbox, that file is load bearing, and its presence alongside a CHANGELOG.md, a CLAUDE.md and a .claude/ directory is a good sign about the project's process.

The AGPL-3.0 licence is the other half of that picture, and for this kind of application it is the licence that keeps a modified client from being shipped closed. A Gmail client is mostly a rendering of a service, and the value of the copyleft is that anyone who improves it has to publish that improvement. That is a different trade from a permissively licensed project, and it is the same choice made by the Electron ecosystem's larger tools.

The test setup shows the same care about credentials. The end-to-end suite signs in to a real account, which is why MERU_TEST_ACCOUNT_EMAIL and MERU_TEST_PROFILE_DIR exist and why the comment says the tests that need them skip rather than fail when the values are absent. A test that signs into a real Gmail account and reads real mail is a test that has to be handled carefully, and the design of skipping rather than failing is the right instinct.

The Pro licence key is handled the same way, in its own environment file, so the licence validation path is tested separately from the free path and the credentials for each are stored separately from the build signing credentials.

Where Meru is the wrong tool

The limits are the ordinary limits of an Electron application wrapping somebody else's service, and they are worth stating plainly.

The first is that it is a client for one service, and the rename notwithstanding, everything the app does depends on Gmail. There is no server component in this repository, so there is nothing here to self-host, nothing to extend with your own data source, and nothing that works if Google changes the web interface. The app is a shell around a web application, and that is the definition of the category.

The second is the trust requirement. Meru holds a logged-in Google session, which means it holds the keys to a mailbox that in most organisations contains everything. The README's own disclaimer and the SECURITY.md file are the right signals, but a user has to decide whether they trust an AGPL community project with that, and a corporate security team will have a policy answer before the user has a personal one.

The third is the platform coverage of the signed builds. The macOS path needs a full Apple signing and notarisation setup with seven values, the Windows path needs an Azure Artifact Signing tenant, and the environment file marks each group as all or none, meaning a partial configuration is not a degraded build but a broken one. So the practical consequence of a fork is that producing distributable, signed artefacts for macOS and Windows is a piece of infrastructure work, and the arm64-only, non-notarised dmg target is the fallback for anyone who does not have it.

The fourth is that the current release line is a beta cut daily. Three beta builds on three consecutive days in October 2026, and the manifest version at 3.63.2 against releases labelled 3.64.0 beta, means the version in the tree and the published artefacts are not obviously in step. For a daily driver that is acceptable, and for an organisation that pins its tooling, it is a reason to pin a specific tag and check what it contains.

The fifth is the Pro tier's opacity. The repository proves there is a Pro licence key, a trial environment and a separate test mode, and describes none of what they unlock. A reader who wants to know what the paid version adds has to look at the product site rather than the code, which is a reasonable commercial choice and a gap in the technical documentation.

Editorial conclusion

Meru is worth adopting for anyone who lives in Gmail and wants it out of the browser tab, because the multi-account window model and the native integrations are the point, and the build system is set up well enough that a fork can produce signed, notarised builds for three platforms. It is the wrong tool if you need anything other than a client for one mailbox, since there is no server component, and the wrong tool for a team that cannot accept a third-party app holding a Google account session, which the disclaimer explicitly says this is. Before installing, check what the Pro tier changes, because the repository tests a Pro licence key separately, and read SECURITY.md, since the app holds live account credentials.

Frequently asked questions

What is Meru?

Meru, formerly Gmail Desktop, is a third-party Gmail desktop app for macOS, Windows and Linux, built with Electron and TypeScript. It puts a mailbox in a native window, supports light and dark appearances, and can show tabs for multiple accounts, and the project states it is not affiliated with Google.

How is Meru built and packaged?

It is a Bun monorepo of TypeScript with React in the front end, packaged by electron-builder. There are separate build scripts for Linux, macOS, macOS dmg and Windows, and the macOS build runs a signing-env script first, while the dmg target targets arm64 and disables notarization and update info.

What are the .env.op files in the Meru repository?

They are the working environment files for the sensitive configurations, alongside the .env.example template. The example lists values for a signed and notarised macOS build, for a signed Windows build through Azure Artifact Signing, for the end-to-end suite's Pro licence key, and for the account and profile directory the end-to-end tests sign in to.

Does Meru have a paid tier?

The repository tests one separately, since .env.example describes MERU_TEST_LICENSE_KEY as the end-to-end suite's Pro licence key without which the Pro tests fail, and there is a separate .env.license.op environment. The README does not describe what the Pro tier adds.

How are Meru's releases versioned?

The recent releases are v3.64.0-beta.4, v3.64.0-beta.3 and v3.64.0-beta.2, cut on consecutive days in October 2026, while the package manifest carries version 3.63.2. The project is marked private in the manifest and the last push was on 2026-10-15.

Official sources

  1. License: AGPL-3.0
  2. Project website
  3. README
  4. Releases
  5. zoidsh/meru on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zoidsh-meru.svg)](https://hysenlabs.com/projects/zoidsh-meru)

Was this useful?