### Configuration

# Configuration

Lepton reads user configuration from a `.leptonrc` JSON file in the home directory reported by Electron. In Lepton v1.9.0 and later, the exact path is shown on the About page (`Command/Ctrl + ,`).

The file is not generated automatically. Create it if you want to override the defaults below.

## Template `.leptonrc`

```json
{
  "theme": "light",
  "autoUpdate": false,
  "startAtLogin": false,
  "i18n": {
    "locale": "en"
  },
  "window": {
    "closeToTray": false,
    "minimizeToTray": false
  },
  "avatar": {
    "type": "github",
    "boringAvatarVariant": "beam"
  },
  "userPanel": {
    "hideProfilePhoto": false
  },
  "logger": {
    "level": "info"
  },
  "security": {
    "cachedAccessTokenStorage": "auto"
  },
  "proxy": {
    "enable": false,
    "address": "socks://localhost:1080"
  },
  "snippet": {
    "sorting": "updated_at",
    "sortingReverse": true,
    "expanded": true,
    "newSnippetPrivate": false,
    "downloadAll": false
  },
  "tag": {
    "showInSnippetList": false,
    "colored": false
  },
  "editor": {
    "tabSize": 4,
    "validateFilename": true
  },
  "enterprise": {
    "enable": false,
    "host": "",
    "token": "",
    "avatarUrl": ""
  },
  "notifications": {
    "success": true,
    "failure": true
  },
  "zoom": {
    "percent": 100
  },
  "shortcuts": {
    "keyShortcutForSearch": "Shift+Space",
    "keyNewGist": "CommandOrControl+N",
    "keyEditGist": "CommandOrControl+E",
    "keyDeleteGist": "CommandOrControl+Delete",
    "keySubmitGist": "CommandOrControl+S",
    "keyImmersiveMode": "CommandOrControl+I",
    "keyAboutPage": "CommandOrControl+,",
    "keyDashboard": "CommandOrControl+D",
    "keySyncGists": "CommandOrControl+R"
  }
}
```

## Options

| Field | Sub-field | Default | Description |
| :--- | :--- | :--- | :--- |
| `theme` | | `light` | UI theme. Supported values: `light`, `dark`, `one-dark`, `atom-one-dark`, `github-light`, `github-dark`, `catppuccin-latte`, `catppuccin-mocha`, `solarized-light`, `solarized-dark`, `dracula`, `material-theme`, `ayu`. |
| `autoUpdate` | | `false` | Enable automatic update downloads for packaged releases. |
| `startAtLogin` | | `false` | Start Lepton when the user logs in. Not supported on every Linux environment. |
| `i18n` | `locale` | `en` | Interface language. Supported values: `en`, `es`, `fr`, `ja`, `ko`, `tr`, `zh-Hans`, `zh-Hant`. |
| `window` | `closeToTray` | `false` | Hide Lepton to the tray/menu bar when the window is closed. On macOS, the normal close behavior hides the window without creating a tray item unless this is enabled. |
| | `minimizeToTray` | `false` | Hide Lepton to the tray/menu bar when the window is minimized. Currently applies on macOS. |
| `avatar` | `type` | `github` | Profile image source. Use `github` for the GitHub avatar or `boring` for a generated avatar. |
| | `boringAvatarVariant` | `beam` | Variant used when `avatar.type` is `boring`. |
| `userPanel` | `hideProfilePhoto` | `false` | Hide the profile photo in the user panel. |
| `logger` | `level` | `info` | Logging level. Use `info` for normal use or `debug` when collecting diagnostic logs. |
| `security` | `cachedAccessTokenStorage` | `auto` | Cached GitHub OAuth token storage. Supported values: `auto`, `encrypted`, `file`. `auto` uses file storage in development builds and Electron safeStorage in packaged builds. |
| `proxy` | `enable` | `false` | Route GitHub API requests and Electron sessions through a proxy. |
| | `address` | `socks://localhost:1080` | Proxy address. Supports normal proxy URLs, Chromium proxy rule lists, and `pac+https://...` PAC URLs. |
| `snippet` | `sorting` | `updated_at` | Snippet order. Supported values: `updated_at`, `created_at`, `description`. |
| | `sortingReverse` | `true` | Reverse the configured snippet order. |
| | `expanded` | `true` | Expand snippets in the detail view by default. |
| | `newSnippetPrivate` | `false` | Create new snippets as secret snippets by default. |
| | `downloadAll` | `false` | Load all authenticated snippets and download their details during sync. Enable this for complete global content search across snippet file contents. |
| `tag` | `showInSnippetList` | `false` | Show custom tags in snippet list rows. |
| | `colored` | `false` | Render custom tags with stable color badges. |
| `editor` | `tabSize` | `4` | Tab size in spaces. |
| | `validateFilename` | `true` | Validate snippet filenames before saving. |
| `enterprise` | `enable` | `false` | Enable GitHub Enterprise mode. |
| | `host` | `""` | GitHub Enterprise host, for example `github.example.com`. |
| | `token` | `""` | Personal access token with the `gist` scope. This remains plain `.leptonrc` configuration and is not affected by `security.cachedAccessTokenStorage`. |
| | `avatarUrl` | `""` | Optional avatar image URL for GitHub Enterprise users. |
| `notifications` | `success` | `true` | Show notifications for successful actions. |
| | `failure` | `true` | Show notifications for failed actions. |
| `zoom` | `percent` | `100` | Default page zoom percentage. `100` is original size; use values like `80`, `120`, or `150`. |
| `shortcuts` | `keyShortcutForSearch` | `Shift+Space` | Open snippet metadata and downloaded-content search. |
| | `keyNewGist` | `CommandOrControl+N` | Create a snippet. |
| | `keyEditGist` | `CommandOrControl+E` | Edit the selected snippet. |
| | `keyDeleteGist` | `CommandOrControl+Delete` | Delete the selected snippet. |
| | `keySubmitGist` | `CommandOrControl+S` | Submit editor changes. |
| | `keyImmersiveMode` | `CommandOrControl+I` | Toggle immersive mode. |
| | `keyAboutPage` | `CommandOrControl+,` | Open the About page. |
| | `keyDashboard` | `CommandOrControl+D` | Open the dashboard. |
| | `keySyncGists` | `CommandOrControl+R` | Sync snippets with GitHub Gist. |

## Debug Logging

Set `logger.level` to `debug` when collecting logs for an issue report:

```json
{
  "logger": {
    "level": "debug"
  }
}
```

## Home Directory Notes

### macOS

On macOS, the home directory is your user folder under `/Users`. Place `.leptonrc` here:

```text
/Users/<CurrentUserName>/.leptonrc
```

In Finder, use `Go` > `Home` to open the home directory. Because `.leptonrc` starts with a dot, it is hidden by default; press `Command + Shift + .` to show hidden files.

### Windows

The home directory can vary by Windows distribution, but it usually starts here:

```text
C:\Users\<CurrentUserName>\.leptonrc
```

Use the About page (`Command/Ctrl + ,`) to find the exact path.

### Linux Snap Package

For the snap package, Electron may report `~/snap/lepton/current` as the home directory instead of `~`. Use the About page (`Command/Ctrl + ,`) to find the exact path.

## Questions Or Issues

Open issues and feature requests at https://github.com/hackjutsu/Lepton/issues.

---

### Faq

# FAQ

## Why Is The Language Of My Snippet "Other"?

Lepton depends on GitHub's API to detect snippet language. If GitHub cannot classify the language, Lepton marks it as `Other`.

You can add a Vim modeline at the top of the snippet to give GitHub a language hint:

```js
// vim: syntax=javascript
let test = 'This is a javascript file'
```

## Search

The default search shortcut is `Shift + Space`.

Lepton can search these fields:

- filename
- language
- description
- tag
- snippet id
- downloaded snippet file content

Complete global content search across every snippet requires the
`snippet.downloadAll` option to be enabled before syncing. When `downloadAll` is
disabled, content search only covers snippets whose details and file content have
already been downloaded locally, such as snippets opened during the session.

See [Configuration](configuration.md#options) for the `snippet.downloadAll` option.

## Title And Tags

Use this pattern in the snippet description to set a title and custom tags:

```text
[title] description #tag1 #tag2
```

Legacy tag syntax is also supported:

```text
[title] description #tags: tag1, tag2
```

## What Is `.leptonrc`, And Where Should I Put It?

`.leptonrc` is Lepton's user configuration file. It is parsed when the app starts and is not created automatically.

Create `.leptonrc` in the home directory reported by Electron. In Lepton v1.9.0 and later, the exact path is shown on the About page (`Command/Ctrl + ,`).

See [Configuration](configuration.md) for the current template and option list.

## How Do I Add A New Interface Locale?

Adding a locale touches both the renderer catalog and the packaged Electron
locale resources:

1. Add `app/utilities/i18n/locales/<locale>.js`, using `en.js` as the complete
   key reference.
2. Import the catalog in `app/utilities/i18n/index.js`, add it to `catalogs`,
   and add the display name to `supportedLocales`.
3. Update `tests/utilities/i18n.test.js` so the new catalog is checked for key
   shape, translated values, and package-locale coverage.
4. Update the supported `i18n.locale` lists in `README.md` and
   `wiki/configuration.md`.
5. Update `configs/electronLanguages.js` if the new Lepton locale needs a
   different Electron/Chromium resource name in packaged apps.
   `electron-builder.js` derives the packaged locale list from
   `getSupportedLocales()`, so do not add a separate hard-coded list to
   `package.json`.
6. Validate with `npm run test:unit` and `npm run test:packaged-smoke`. For
   packaged builds, confirm every Lepton-supported locale is present and
   intentionally unsupported Electron locales are absent.

## Proxy

Put proxy settings in `.leptonrc`:

```json
{
  "proxy": {
    "enable": true,
    "address": "socks://localhost:1080"
  }
}
```

See [Configuration](configuration.md#options) for all proxy-related options.

## Enable GitHub Enterprise

Create a GitHub personal access token with the `gist` scope enabled. Then add your GitHub Enterprise host and token to `.leptonrc`:

```json
{
  "enterprise": {
    "enable": true,
    "host": "github.example.com",
    "token": "token_with_gist_scope",
    "avatarUrl": ""
  }
}
```

See [Configuration](configuration.md#options) for the full `enterprise` option list.

## Scope For GitHub Access Token

Lepton can use token login instead of GitHub OAuth credentials. Create a
GitHub personal access token with the `gist` scope, then paste that token into
Lepton's token login screen.

The fastest path is GitHub's prefilled token page:
[Create a Lepton token with the `gist` scope](https://github.com/settings/tokens/new?description=Lepton&scopes=gist).

If you create the token manually:

1. Open GitHub, then go to Settings -> Developer settings -> Personal access
   tokens -> Tokens (classic).
2. Select Generate new token -> Generate new token (classic).
3. Enter a descriptive note, such as `Lepton`, and choose an expiration.
4. Under Select scopes, enable only `gist`.
5. Click Generate token and copy the token immediately. GitHub only shows it
   once.

For GitHub Enterprise, create the token on your Enterprise host with the same
`gist` scope.

## About Data Collection

Lepton is a desktop snippet client backed by GitHub Gist and does not run its own sync service. Data is stored locally by the app or remotely in GitHub Gist.

## Donation

Lepton does not accept personal donations. If you want to donate, consider donating to the [Wikimedia Foundation](https://wikimediafoundation.org/wiki/Ways_to_Give), which helps sustain free knowledge through Wikipedia and related projects.

You are welcome to create an issue to share how much you contributed.

---

### Publish Flow

# Publish Flow

Lepton publishes desktop builds through the `Release` GitHub Actions workflow.
Merging release-flow changes does not publish anything by itself. Publishing
starts only when a version tag is pushed or when the workflow is run manually.

## Release Types

| Flow | Tag example | GitHub release | Snap channel | Stable users notified |
| :--- | :--- | :--- | :--- | :--- |
| Stable release | `v1.10.2` | Published release | `stable` | Yes, when `autoUpdate` is enabled |
| Prerelease | `v1.11.0-beta.1` | Prerelease | `edge` | No |
| Manual dry run | No tag | No release by default | No store publish by default | No |

Stable tags must be plain semver tags:

```bash
git tag v1.10.2
git push origin v1.10.2
```

Prerelease tags must include a semver prerelease suffix:

```bash
git tag v1.11.0-alpha.1
git push origin v1.11.0-alpha.1

git tag v1.11.0-beta.1
git push origin v1.11.0-beta.1

git tag v1.11.0-rc.1
git push origin v1.11.0-rc.1
```

The workflow rejects tags that do not look like `v1.2.3` or
`v1.2.3-beta.1`.

## Required Secrets

Configure these in GitHub Actions secrets before publishing:

| Secret | Used by | Required for |
| :--- | :--- | :--- |
| `LEPTON_GITHUB_CLIENT_ID` | All packaging jobs | All release builds |
| `LEPTON_GITHUB_CLIENT_SECRET` | All packaging jobs | All release builds |
| `SNAPCRAFT_STORE_CREDENTIALS` | Linux | Snap Store publish |

The workflow uses GitHub's built-in `GITHUB_TOKEN` for GitHub Release uploads.

`configs/account.js` is not committed. Each release job generates it from
`LEPTON_GITHUB_CLIENT_ID` and `LEPTON_GITHUB_CLIENT_SECRET` before packaging so
release artifacts use the configured GitHub OAuth app.

Use GitHub Environments if prerelease and production should have different
secret values or approval rules.

## Stable Release Flow

Use this flow for versions intended for all users.

```text
merge release-ready code to master
    |
    v
create plain semver tag, for example v1.10.2
    |
    v
push tag to origin
    |
    v
Release workflow
    |
    +--> resolve context:
    |       publish_policy=always
    |       github_release_type=release
    |       environment=production
    |       snap_channels=stable
    |
    +--> validate:
    |       npm run lint
    |       npm run test:unit
    |       npm run test:build
    |
    +--> build macOS:
    |       dmg + zip for x64
    |       dmg + zip for arm64
    |       ad-hoc signed, not notarized
    |
    +--> build Windows:
    |       NSIS installer for x64 and ia32
    |       7z archive for x64 and ia32
    |       unsigned by policy
    |
    +--> build Linux:
    |       AppImage for x64
    |       snap for x64
    |
    v
publish GitHub Release and release assets
    |
    v
publish Snap to stable channel
    |
    v
stable auto-update metadata is available
```

The macOS job builds Intel and Apple Silicon artifacts in one electron-builder
run so `latest-mac.yml` is generated once for the full macOS artifact set.

## macOS Gatekeeper And Windows SmartScreen

Lepton does not require paid Apple Developer Program or Windows code-signing
certificates for publishing. macOS artifacts are ad-hoc signed so the app
bundle is structurally valid for local code-signing checks, but they are not
Developer ID signed or notarized. The workflow does not read Apple certificate
secrets.

Expected user-facing behavior:

- macOS users should expect Gatekeeper to say Apple cannot verify Lepton is
  free of malware. They may need to open Lepton from Finder's context menu or
  approve it in Privacy & Security settings.
- If macOS still reports that Lepton is damaged after the app is dragged into
  `/Applications`, advanced users can clear the downloaded-app quarantine flag:
  `xattr -dr com.apple.quarantine /Applications/Lepton.app`.
- Windows users should expect Microsoft Defender SmartScreen warnings until the
  unsigned app has enough reputation.
- macOS and Windows auto-update metadata is still published for stable tags,
  but ad-hoc-signed macOS updates and unsigned Windows updates should be
  manually verified before they are advertised as fully supported update paths.

If Developer ID signing or notarization is added later, update
`.github/workflows/release.yml`, `electron-builder.js`, this wiki page, and the
README together.

Stable app builds are eligible to check for updates when the user's
`.leptonrc` has:

```json
{
  "autoUpdate": true
}
```

Only newer stable versions should notify users. Prerelease candidates are
ignored by the updater policy.

## Prerelease Flow

Use this flow for testing builds that should be public but should not notify
stable users.

```text
merge prerelease-ready code to master
    |
    v
create semver prerelease tag, for example v1.11.0-beta.1
    |
    v
push tag to origin
    |
    v
Release workflow
    |
    +--> resolve context:
    |       publish_policy=always
    |       github_release_type=prerelease
    |       environment=prerelease
    |       snap_channels=edge
    |
    +--> validate:
    |       npm run lint
    |       npm run test:unit
    |       npm run test:build
    |
    +--> build macOS, Windows, and Linux artifacts
    |
    v
publish GitHub prerelease and prerelease assets
    |
    v
publish Snap to edge channel
    |
    v
no stable-user auto-update notification
```

Prerelease app versions do not check for updates. Stable app versions also do
not notify for prerelease update candidates.

## Manual Release Workflow Runs

The workflow can be started manually from the GitHub Actions UI.

Manual inputs:

| Input | Default | Purpose |
| :--- | :--- | :--- |
| `publish` | `never` | Use `never` for a packaging dry run. Use `always` to publish. |
| `release_type` | `draft` | GitHub release type for manual publishing: `draft`, `prerelease`, or `release`. |
| `snap_channels` | `edge` | Comma-separated Snap channels for manual publishing. |

Manual runs default to `publish=never`, so they build artifacts and upload
workflow artifacts without creating a GitHub Release or publishing to the Snap
Store.

## Expected Artifacts

Artifact names include product name, version, operating system, architecture,
and extension:

```text
Lepton-1.10.2-mac-x64.dmg
Lepton-1.10.2-mac-arm64.zip
Lepton-1.10.2-win-x64.exe
Lepton-1.10.2-win-ia32.7z
Lepton-1.10.2-linux-x64.AppImage
Lepton-1.10.2-linux-x64.snap
```

Updater metadata files such as `latest.yml` and `latest-mac.yml` are also
generated and published with GitHub release assets.

## Failure Handling

If validation fails, fix the branch and create a new tag after the fix is
merged. Do not reuse a published version tag unless the failed workflow did not
publish any artifacts.

If publishing partially succeeds:

1. Remove or repair the incomplete GitHub Release assets.
2. Remove incorrect Snap channel revisions or close the affected channel in the
   Snap Store.
3. Create a new patch or prerelease tag.
4. Run the release flow again from the new tag.

Avoid force-moving public release tags after users may have downloaded assets.

## Local Packaging Fallback

Local packaging is still available for diagnosing build issues:

```bash
npm ci
npm run dist -- -m
npm run dist -- -w
npm run dist -- -l
```

Local release-like packaging still needs `configs/account.js` to exist. The
GitHub Actions workflow generates this file from secrets; local builds must
create it manually.

---

### README

# Lepton Wiki

These pages are the canonical, versioned replacement for the old GitHub wiki.

- [Configuration](configuration.md)
- [FAQ](faq.md)
- [Publish Flow](publish-flow.md)

---

### README

[](#contributors-)




[](https://opensource.org/licenses/MIT)
[](https://snapcraft.io/lepton)

**Lepton** is a lean code snippet manager powered by GitHub Gist. [Check out the latest release.](https://github.com/hackjutsu/Lepton/releases)

## Features
- Unlimited public/secret snippets
- Unlimited tags
- Language groups
- Markdown/JupyterNotebook
- [GitHub Enterprise](wiki/faq.md#enable-github-enterprise)
- GitHub token
- Immersive mode
- [Customizable](wiki/configuration.md)
- Built-in themes
- macOS/Win/Linux
- Dashboard
- [Search snippets](wiki/faq.md#search)
- [Proxy](wiki/faq.md#proxy)
- Free



| [Light Theme](https://github.com/hackjutsu/Lepton#customization)     | [Dark Theme](https://github.com/hackjutsu/Lepton#customization)    |
| :-------------:| :-----:|
|||

|      Organize         |  Markdown | Jupyter Notebook |
| :-------------:| :-----:| :-----: |
|  |  |  |

|      Search snippets (*⇧ + Space*)         |    Immersive Mode *(⌘/Ctrl + i)*    | Dashboard *(⌘/Ctrl + d)* |
| :-------------:| :-----:| :-----: |
|  |  | 


## Shortcuts
| Function       | Shortcut       |  Note     |
| :------------: |:-------------: |:-----:|
| New Snippet    | `Cmd/Ctrl + N` | Create a snippet      |
| Edit Snippet   | `Cmd/Ctrl + E` | Edit a snippet      |
| Delete Snippet   | `Cmd/Ctrl + Del` | Delete selected snippet      |
| Submit         | `Cmd/Ctrl + S` | Submit the changes from the editor      |
| Sync           | `Cmd/Ctrl + R` | Sync snippets with GitHub Gist   |
| Immersive Mode | `Cmd/Ctrl + I` |  Toggle the [Immersive mode](https://github.com/hackjutsu/Lepton/blob/master/docs/img/portfolio/immersive.png)    |
| Dashboard      | `Cmd/Ctrl + D` |  Toggle the [dashboard](https://github.com/hackjutsu/Lepton/blob/master/docs/img/portfolio/dashboard.png)     |
| About Page     | `Cmd/Ctrl + ,` |  Toggle the [About page](https://github.com/hackjutsu/Lepton/blob/dev/docs/img/portfolio/about.png)    |
| Search         | `Shift + Space`|  Toggle [snippet search](wiki/faq.md#search)    |

See the [Search FAQ](wiki/faq.md#search) for searchable fields and content-search behavior.

## Customization
Lepton's can be customized by `<home_dir>/.leptonrc`! You can find its exact path in the About page by `Command/Ctrl + ,`. Create the file if it does not exist.

- Theme (`light`, `dark`, `one-dark`, `atom-one-dark`, `github-light`, `github-dark`, `catppuccin-latte`, `catppuccin-mocha`, `solarized-light`, `solarized-dark`, `dracula`, `material-theme`, or `ayu`)
- Snippet
- Editor
- Logger
- Proxy
- Shortcuts
- Zoom
- Enterprise
- Notifications
- Interface language (`i18n.locale`: `en`, `es`, `fr`, `ja`, `ko`, `tr`, `zh-Hans`, or `zh-Hant`)

Check out the [configuration docs](wiki/configuration.md) to explore different customization options.
Missing a locale? See [How do I add a new interface locale?](wiki/faq.md#how-do-i-add-a-new-interface-locale)

## Tech Stack


1. Framework: [Electron](http://electron.atom.io/)
2. Bundler: [Webpack](http://webpack.github.io/docs/), [Babel](https://babeljs.io), [electron-builder](https://github.com/electron-userland/electron-builder)
3. Language: ES6, Sass/SCSS
4. UI/state: React 19, Redux, React Redux, Redux Thunk
5. Editor/rendering: CodeMirror, Highlight.js, Markdown/Jupyter rendering
6. Tests/lint: Vitest, Electron smoke tests, ESLint

Now you can learn about Lepton project's code structure in [DeepWiki](https://deepwiki.com/hackjutsu/Lepton)!

## Installation
- macOS/Windows/Linux: Download [the released packages](https://github.com/hackjutsu/Lepton/releases)
- macOS: Install via Homebrew
```bash
brew install --cask lepton
```
- Linux: Install via [Snap Store](https://snapcraft.io/lepton)
```bash
snap install lepton
```


## Support
Lepton is a free and open source project. We do not accept project donations, but if you would like to support the maintainer, you can [buy me a coffee](https://www.buymeacoffee.com/cosmolepton).

<a href="https://www.buymeacoffee.com/cosmolepton"><img src="https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20coffee&emoji=&slug=cosmolepton&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" alt="Buy me a coffee" /></a>

We also recommend donating to [Wikimedia Foundation](https://donate.wikimedia.org/wiki/Ways_to_Give), which helps sustain free knowledge through Wikipedia and its sister projects.

## Development

### Runtime requirements

Lepton's current development toolchain is known to work with Node.js 24 LTS and
npm 11.x. This is the host runtime used to install dependencies and run the
webpack build; the bundled Electron app runtime is managed by the Electron
version in `package.json`.

Recommended:

- Node.js 24.18.0
- npm 11.16.x

If you use `nvm`, the repository includes an `.nvmrc`:

```bash
$ nvm install
$ nvm use
```

Apple Silicon development should use the native arm64 Node.js runtime.

### Install dependencies

```bash
$ git clone https://github.com/hackjutsu/Lepton.git
$ cd Lepton
$ npm ci
```

```bash
# inspect stale dependencies
$ npm run check-outdated
```

### Client ID/Secret
[Register your application](https://github.com/settings/applications/new), and put your client id and client secret in `./configs/account.js`.
```js
module.exports = {
  client_id: <your_client_id>,
  client_secret: <your_client_secret>
}
```

`configs/account.js` is intentionally ignored by Git. If it is missing, the app
falls back to `configs/accountDummy.js`, which is useful for rendering tests but
will not support real GitHub login. Release builds create `configs/account.js`
from GitHub Actions secrets before packaging.

### Run
```bash
$ npm run build && npm start
```

For iterative renderer work, run webpack in watch mode in one terminal and
restart Electron from another terminal when needed:

```bash
$ npm run webpack-watch
$ npm start
```

### Build

```bash
# Development bundle
$ npm run build

# Production bundle
$ npm run webpack-prod
```

### Automated Validation

Use these commands before opening a pull request:

```bash
# Lint application source
$ npm run lint

# Normal local check: Vitest unit tests plus webpack development build
$ npm test

# Unit tests only
$ npm run test:unit

# Unit tests in watch mode
$ npm run test:unit:watch
```

The project also has Electron smoke checks. These are useful for Electron,
React, layout, preload, or packaging changes, and are run by CI.

```bash
# Launches Electron with isolated config/user-data and verifies login plus
# fixture-backed authenticated renderer surfaces
$ npm run test:smoke

# Builds an unpacked app and verifies the packaged app can render the login UI.
# This is primarily for macOS CI or release verification.
$ npm run test:packaged-smoke
```

Renderer smoke fixtures are opt-in through the smoke runner and use deterministic
mock state to check initial rendering. Fixture names include `active`, `edit`,
`new`, `about`, `dashboard`, `search`, `delete`, `raw`, `pinned-tags`, and
`immersive`.

```bash
# Launch one fixture directly when debugging the automated smoke check
$ npm run build
$ LEPTON_RENDER_FIXTURE=active npm start
```

Fixtures verify that important React surfaces mount without renderer warnings,
errors, failed loads, or crashes. They do not verify GitHub OAuth, snippet CRUD,
sync behavior, real API responses, OS shortcut delivery, or full interaction
flows.

GitHub Actions currently runs:

- `lint-test-build`: lint, unit tests, and webpack build verification
- `electron-smoke`: Electron renderer smoke test
- `packaged-smoke`: packaged app smoke test
- `release`: tag-driven cross-platform packaging and publishing

The smoke jobs are currently configured as non-blocking CI checks while the
cross-platform Electron validation continues to mature.

### Manual Verification

For UI or Electron changes, also launch the app locally:

```bash
$ npm run build && npm start
```

Confirm the login page visibly renders. After login, manually verify the
surfaces affected by your change, such as new snippet, edit snippet,
settings/about, dashboard, search, sync, and GitHub Gist backend interactions.
Manual verification is still required for visual quality and real GitHub
behavior; automated smoke checks do not replace backend workflow testing.

## Local Packaging

Build an unpacked app for the current platform.
```bash
$ npm run pack
```
Build apps for macOS.
```bash
$ npm run dist -- -m
```
Build apps for Windows.
```bash
$ npm run dist -- -w
```
Build apps for Linux.

>Need a running [Docker](https://www.docker.com/) daemon to build a `snap` package.
```bash
$ npm run dist -- -l
```
Build apps for macOS, Windows and Linux.
```bash
$ npm run dist -- -wml
```
Build apps for the current OS with the current arch.
```bash
$ npm run dist
```

## FAQ
[--> Wiki FAQ](wiki/faq.md)

## Contributors



<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://airbnb.io/"><img src="https://avatars3.githubusercontent.com/u/7756581?v=4?s=100" width="100px;" alt="CosmoX"/><br /><sub><b>CosmoX</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=hackjutsu" title="Code">💻</a> <a href="#design-hackjutsu" title="Design">🎨</a> <a href="https://github.com/hackjutsu/Lepton/commits?author=hackjutsu" title="Tests">⚠️</a> <a href="#maintenance-hackjutsu" title="Maintenance">🚧</a> <a href="#platform-hackjutsu" title="Packaging/porting to new platform">📦</a> <a href="#ideas-hackjutsu" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://loveac.cn"><img src="https://avatars1.githubusercontent.com/u/5550402?v=4?s=100" width="100px;" alt="Jiaye Wu"/><br /><sub><b>Jiaye Wu</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=wujysh" title="Code">💻</a> <a href="#maintenance-wujysh" title="Maintenance">🚧</a> <a href="#ideas-wujysh" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/DNLHC"><img src="https://avatars1.githubusercontent.com/u/14959483?v=4?s=100" width="100px;" alt="Danila"/><br /><sub><b>Danila</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=DNLHC" title="Code">💻</a> <a href="#design-DNLHC" title="Design">🎨</a> <a href="#maintenance-DNLHC" title="Maintenance">🚧</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.meilinzhan.com/"><img src="https://avatars2.githubusercontent.com/u/13786673?v=4?s=100" width="100px;" alt="Meilin Zhan"/><br /><sub><b>Meilin Zhan</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=meilinz" title="Code">💻</a> <a href="#ideas-meilinz" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-meilinz" title="Maintenance">🚧</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/liuchenguang"><img src="https://avatars1.githubusercontent.com/u/5697293?v=4?s=100" width="100px;" alt="lcgforever"/><br /><sub><b>lcgforever</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=lcgforever" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/passerbyid"><img src="https://avatars1.githubusercontent.com/u/2075566?v=4?s=100" width="100px;" alt="Yuer Lee"/><br /><sub><b>Yuer Lee</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=passerbyid" title="Documentation">📖</a> <a href="#platform-passerbyid" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://yysu.github.io/About-me"><img src="https://avatars3.githubusercontent.com/u/12994810?v=4?s=100" width="100px;" alt="Su,Yen-Yun"/><br /><sub><b>Su,Yen-Yun</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=YYSU" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://cixuuz.github.io/"><img src="https://avatars3.githubusercontent.com/u/26782336?v=4?s=100" width="100px;" alt="Chen Tong"/><br /><sub><b>Chen Tong</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=cixuuz" title="Code">💻</a> <a href="#ideas-cixuuz" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-cixuuz" title="Maintenance">🚧</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Gisonrg"><img src="https://avatars0.githubusercontent.com/u/4332224?v=4?s=100" width="100px;" alt="Jason Jiang"/><br /><sub><b>Jason Jiang</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=Gisonrg" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://popey.com/"><img src="https://avatars0.githubusercontent.com/u/1841272?v=4?s=100" width="100px;" alt="Alan Pope"/><br /><sub><b>Alan Pope</b></sub></a><br /><a href="#platform-popey" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://tonyxu.io"><img src="https://avatars3.githubusercontent.com/u/6280136?v=4?s=100" width="100px;" alt="Tony Xu"/><br /><sub><b>Tony Xu</b></sub></a><br /><a href="#platform-tonyxu-io" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://tegan.lol"><img src="https://avatars0.githubusercontent.com/u/13814048?v=4?s=100" width="100px;" alt="Tegan Churchill"/><br /><sub><b>Tegan Churchill</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=rawrmonstar" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/AngieW0908"><img src="https://avatars3.githubusercontent.com/u/26016229?v=4?s=100" width="100px;" alt="Angie Wang"/><br /><sub><b>Angie Wang</b></sub></a><br /><a href="#design-AngieW0908" title="Design">🎨</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://batuhanbayrakci.com"><img src="https://avatars0.githubusercontent.com/u/965804?v=4?s=100" width="100px;" alt="Batuhan Bayrakci"/><br /><sub><b>Batuhan Bayrakci</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=baybatu" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://samuelmeuli.com"><img src="https://avatars0.githubusercontent.com/u/22477950?v=4?s=100" width="100px;" alt="Samuel Meuli"/><br /><sub><b>Samuel Meuli</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=samuelmeuli" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/alexandreamadocastro"><img src="https://avatars2.githubusercontent.com/u/5918765?v=4?s=100" width="100px;" alt="Alexandre Amado de Castro"/><br /><sub><b>Alexandre Amado de Castro</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=alexandreamadocastro" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://abner.space/"><img src="https://avatars2.githubusercontent.com/u/1998649?v=4?s=100" width="100px;" alt="Abner Soares Alves Junior"/><br /><sub><b>Abner Soares Alves Junior</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=abnersajr" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://seanz.me"><img src="https://avatars0.githubusercontent.com/u/5442563?v=4?s=100" width="100px;" alt="Sean"/><br /><sub><b>Sean</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=seancheung" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/moia-sven-ole"><img src="https://avatars0.githubusercontent.com/u/32508538?v=4?s=100" width="100px;" alt="Ole"/><br /><sub><b>Ole</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=moia-sven-ole" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/GabrielNicolasAvellaneda/"><img src="https://avatars3.githubusercontent.com/u/1248101?v=4?s=100" width="100px;" alt="Gabriel Nicolas Avellaneda"/><br /><sub><b>Gabriel Nicolas Avellaneda</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=GabrielNicolasAvellaneda" title="Code">💻</a> <a href="https://github.com/hackjutsu/Lepton/commits?author=GabrielNicolasAvellaneda" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://dideler.github.io"><img src="https://avatars2.githubusercontent.com/u/497458?v=4?s=100" width="100px;" alt="Dennis Ideler"/><br /><sub><b>Dennis Ideler</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=dideler" title="Code">💻</a> <a href="#ideas-dideler" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/hackjutsu/Lepton/commits?author=dideler" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="http://AnthonyAttard.com"><img src="https://avatars0.githubusercontent.com/u/8838135?v=4?s=100" width="100px;" alt="Anthony Attard"/><br /><sub><b>Anthony Attard</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=anthonyattard" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://ArLEquiN64.github.io/"><img src="https://avatars1.githubusercontent.com/u/7821318?v=4?s=100" width="100px;" alt="ArLE"/><br /><sub><b>ArLE</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=ArLEquiN64" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.polnetwork.com"><img src="https://avatars1.githubusercontent.com/u/639877?v=4?s=100" width="100px;" alt="Pol Maresma"/><br /><sub><b>Pol Maresma</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=polnetwork" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://blog.jubeat.net"><img src="https://avatars.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt="PM Extra"/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=PMExtra" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://zava.carrd.co/"><img src="https://avatars.githubusercontent.com/u/1155199?v=4?s=100" width="100px;" alt="Zava"/><br /><sub><b>Zava</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=EdZava" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/jasonralexander"><img src="https://avatars.githubusercontent.com/u/1030838?v=4?s=100" width="100px;" alt="Jason R Alexander"/><br /><sub><b>Jason R Alexander</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=sunnysidesounds" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://irrelevant.at"><img src="https://avatars.githubusercontent.com/u/279378?v=4?s=100" width="100px;" alt="Sebastian Hojas"/><br /><sub><b>Sebastian Hojas</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=Sebastian-Hojas" title="Documentation">📖</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/yuhang-dong"><img src="https://avatars.githubusercontent.com/u/20642641?v=4?s=100" width="100px;" alt="董雨航"/><br /><sub><b>董雨航</b></sub></a><br /><a href="https://github.com/hackjutsu/Lepton/commits?author=yuhang-dong" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://sxyz.blog"><img src="https://avatars.githubusercontent.com/u/17523360?v=4?s=100" width="100px;" alt="sxyazi"/><br /><sub><b>sxyazi</b></sub></a><br /><a href="#platform-sxyazi" title="Packaging/porting to new platform">📦</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://megabyte.space"><img src="https://avatars.githubusercontent.com/u/59970525?v=4?s=100" width="100px;" alt="Brian Zalewski"/><br /><sub><b>Brian Zalewski</b></sub></a><br /><a href="#platform-ProfessorManhattan" title="Packaging/porting to new platform">📦</a></td>
    </tr>
  </tbody>
</table>






## License
MIT © [hackjutsu](https://github.com/hackjutsu)

---