尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证A free, full-screen Launchpad-style app grid for macOS 14+: pages, folders and type-to-search, one keystroke away.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A free, full-screen app grid for macOS 14+: pages, folders and type-to-search, one keystroke away. Everything is included; there are no purchases, licence checks, network calls or announcements.
About 99% of LaunchGrid (code, tests, documentation and website) was written by AI, Claude by Anthropic, directed and tested by Sébastien Lavoie. The app itself contains no AI features and makes no network connections.
Download LaunchGrid.zip from the latest release, unzip it and move LaunchGrid to your Applications folder. Or use Homebrew: brew install --cask sglavoie/tap/launchgrid, and brew upgrade for updates. It is signed and notarised, and runs on Apple silicon and Intel Macs with macOS 14 or later.
scripts/bundle.sh # release build → build/LaunchGrid.app (ad-hoc signed, hardened runtime)
open build/LaunchGrid.app
scripts/install.sh # build, quit the installed copy, replace /Applications/LaunchGrid.app, relaunch
swift test # core and app-state tests
With just, just lists shortcuts for these: just install, just uninstall (removes the login item, quits and deletes the app, keeps your layout and settings), just run, just scratch (a throwaway layout and separate settings, beside the installed copy, logs in the terminal), just sandbox (the build signed with the Mac App Store sandbox, run as a first launch: its container is set aside and put back when it quits, and just sandbox --keep keeps it instead; quit the installed copy first), just test, just test-app-store, just ci and just clean.
CI (.github/workflows/ci.yml) builds, tests and bundles on macOS 26, runs the tests again against the Mac App Store variant (just test-app-store) and checks scripts/*.sh with shellcheck.
just test-ui builds a debug bundle and runs the UI regression scenarios in scripts/ui-tests.
Run it on a test Mac with a logged-in graphical session, including over SSH: it opens windows
and sends keyboard and mouse events through the app. Each scenario has a fixed fixture catalog,
a fresh layout and a unique settings domain; it leaves your installed layout and interactive
scratch settings alone. It does not start scans, folder watchers or the global shortcut. Keep
the test session idle while it runs. No Screen Recording or Accessibility permission is needed.
just test-ui --no-build reuses the bundled app; append a scenario path to run just that case.
State assertions wait up to three seconds, and each process has a 60-second timeout (override
with UI_TEST_TIMEOUT). Logs, the scenario, the final state/layout and a JSON result stay in
build/ui-tests/<run>/<scenario>/; failures also capture the app's window contents, including
hidden windows. CI runs the scenarios against the downloadable bundle and uploads artifacts
on failure. The runner is compiled out of the Mac App Store build. See
scripts/ui-tests/README.md for adding scenarios.
The website at launchgrid.sglavoie.com (home, support and privacy policy) is static HTML in website/public, served by a Cloudflare Worker: just website previews it. Pushing a change under website/ to main publishes it (.github/workflows/website.yml), after scripts/check-website.sh confirms that every file and #anchor the pages refer to exists (pull requests run the same check); just website-deploy does the same by hand. docs/app-store-submission.md tracks what the Mac App Store still needs. The video and Settings screenshots on the home page come from just demo-video (scripts/record-demo.sh), which drives a scratch copy through scripts/demo/story.txt and scripts/demo/settings.txt with the apps in scripts/demo/apps.txt; edit those and run it again to refresh them. It needs ffmpeg, cwebp and Screen Recording permission for the terminal you run it in.
Installing to /Applications is needed for "Open at login". scripts/install.sh --no-open skips the relaunch, and INSTALL_DIR=~/Applications installs elsewhere. It falls back to sudo when the folder isn't writable, and registers the installed copy as the .launchgrid handler. Only the copy at the install path is quit (LaunchGrid saves and quits on SIGTERM), so a just scratch run keeps going.
Release a new version from a clean main checkout with one command:
just release patch # 1.0.1 → 1.0.2
just release minor # 1.0.1 → 1.1.0
just release major "Release notes" # 1.0.1 → 2.0.0; notes are optional
These commands bump VERSION in scripts/bundle.sh, commit it, push main to origin (including any local commits), wait for that commit's CI to pass, build the signed and notarised universal app, create the GitHub release and update the Homebrew cask in sglavoie/homebrew-tap. They require an authenticated gh, your Developer ID in the keychain (or SIGN_IDENTITY), the notarisation credentials described in scripts/release.sh, and a clean tap clone. The scripts use TAP_DIR when set, otherwise look for ../homebrew-tap or ../sglavoie_homebrew-tap; if neither exists, they clone sglavoie/homebrew-tap into ../homebrew-tap automatically. If interrupted after the version commit, fix the failure and run just release resume with any release notes again; it keeps the current version and reuses the zip when it belongs to the current commit. If only the cask update failed, just publish retries it directly.
just release with no arguments still only builds build/release/LaunchGrid.zip; just publish publishes that build and updates Homebrew. This also supports manually editing the version, committing and pushing before building once CI passes. release.sh and app-store.sh check CI; after a documentation-only or website-only push whose tests were skipped, they look back to the commit whose tests ran. SKIP_CI_CHECK=1 skips the CI wait and check. The downloadable build is not sandboxed, so it can scan any folder and read the old Launchpad/AppGrid databases without asking.
just app-store (scripts/app-store.sh) makes the Mac App Store build: the same code in the App Sandbox (scripts/LaunchGrid.entitlements), without the debug scripts, signed with Apple Distribution and packaged as build/app-store/LaunchGrid.pkg; just app-store --upload sends it to App Store Connect and tags the commit app-store/vVERSION, so neither script builds that version again from another commit. The script's header describes the certificates and provisioning profile it needs. Inside the sandbox, LaunchGrid keeps security-scoped bookmarks to the extra scan folders, the custom background picture and apps added with Browse (FileAccess in Services.swift), and the AppGrid and Launchpad imports first ask for the database's folder. ~/Applications is read through a temporary-exception entitlement. Both builds ship scripts/PrivacyInfo.xcprivacy.
On first launch, a welcome window lets you choose which installed apps to include (all by default), then offers these ways to set up the grid:
| Show / hide | ⌥Space (change in Settings), the menu-bar icon, or the Dock icon. Both icons' menus (right-click) hold Settings, Add Missing Apps, Sort Everything, grid files, imports, Rebuild from Scratch and About |
| Launch | Click, or arrow keys + Return |
| Search | Just type. Results rank prefix > word start > initials ("vsc") > substring > fuzzy. Return opens the first result; ⌘F clears the search to start again |
| Pages | Swipe, scroll (up and down too), ⌘←/→, Tab / ⇧Tab, Page Up/Down, Home/End (first and last page), ⌘1…9, click the page dots. Plain ←/→ turn the page too before an item has focus or past a page's end. ⌘N adds a page after the current one |
| Esc | Clears search → closes folder (focus returns to it) → leaves edit mode → clears the selection → hides |
| Edit mode | ⌘E, long-press an icon, or ⋯ › Edit Layout. Clicking selects instead of launching; clicking a search result (or Return) shows it where it is, its folder open, with keyboard focus on it. ✕ removes an item; with the keyboard, Return opens the focused folder and renames the focused app (or the open folder, so Return twice renames a folder), ⌫ removes it and ⌥ + arrow keys move it (with the rest of the selection) one slot, onto the next or previous page past either end |
| Select | ⌘-click / ⇧-click, ⌘A, or Space on the focused item. Then drag them together, Group (⌘G), Remove (⌫), or Move to Page |
| Drag & drop | Drop in a gap to reorder. Hold over an app for a moment to make a folder, or over a folder to add to it. Hold at the screen edge to flip pages, including onto a new page. Drag out of an open folder to take an app out |
| Folders | Click the title to rename. Ungroup from the context menu. A folder disappears when its last app leaves |
| Undo / redo | ⌘Z / ⇧⌘Z, 50 levels, including imports, rebuilds and resizes |
| Other keys | ⌘, opens Settings, ⌘W hides, ⌘Q quits |
| Actions | Grid items that open a link or deep link, a file or folder (optionally with a chosen app), an Apple Shortcut, or run a shell command or one of your scripts (see Actions). Create one with New Action… in the ⋯ or background menu (it goes on that page) or the menu-bar and Dock menus; edit one with Edit Action… in its context menu, ⌘I, or Return in edit mode; Settings › Library lists them all. An action's find it first in search: with in its link, Shortcut input, command or script arguments, typing and Return runs it with in place of . Turn off to keep it to search only. runs it from the editor before saving; each save is one undo step. Opening a link hands it to your browser; LaunchGrid itself makes no connection |
Settings:
.launchgrid files (double-clicking one in Finder loads it too; .appgrid files from earlier builds still load), import from AppGrid or Launchpad, rebuild, regenerate icons.An action is a grid item you make, next to apps and folders: it can be placed, moved, renamed, searched for and undone like an app (folders hold only apps for now). Its kind says what it does:
https://…, obsidian://…, x-callback-url://…) with the app that handles it. LaunchGrid itself makes no connection./bin/zsh -l -c, a login shell) in the background, where a badge on the tile shows it running or failed and Show Last Output… keeps the last 4 KB of its output and errors, or in a terminal (Terminal, iTerm, Ghostty or another app, set in Settings › General › Actions). Background commands stop after a time limit (60 s unless set) and can be stopped from the tile's menu. Downloadable build only.~/Library/Application Scripts/com.sglavoie.launchgrid/ (create it if it doesn't exist; Open Scripts Folder in the editor opens it), with arguments one per line. It must be executable (chmod +x), or an AppleScript (.scpt, .applescript). Works in both builds.Keywords (comma-separated) put an action first in search, so a keyword and Return runs it; a keyword followed by text passes that text as the argument, which replaces {query} in a link (URL-encoded), a Shortcut's input, a command (as text the shell never runs, even inside quotes; the editor refuses {query} in backticks, ${…}, arithmetic ($((…)), ((…)), $[…], subscripts like a[…] or $#[…], even quoted), [[ … ]] tests that compare numbers or use -v or -t, glob qualifiers like *(e:'…':), or here-documents, also when a \ at the end of a line splits their operators across lines, and mixed into code another program runs: after -c, -e (or -pe and the like) of a shell, osascript, sed or a scripting language, in a sed or awk program given without -e, in eval, trap, watch or ssh (past the first word of the command they join, even as a whole argument: eval echo {query}), in a <(…) that a shell runs as its script, or in input piped, redirected or given with <<< to a shell, osascript, a scripting language or at that reads its program from it (echo '…{query}…' | osascript), where that program would run what's typed (as a whole argument, sh -c {query}, it is run on purpose), or as an argument of builtins that evaluate it even quoted: let, integer, float, repeat, shift, exit, return, read, unset and vared, a variable name for typeset, declare, local or export (export X={query} is fine), printf with a number format like %d, and print -v or printf -v, or as the value of a variable that holds a number, declared anywhere in the command (typeset -i n and then n={query}) or one of zsh's own like SECONDS) or a script argument (as is). Commands and scripts also get it in (except scripts in the Mac App Store build); a command that reads takes an argument even without . Turn off for a action, kept in the layout but on no page.
The two builds. The downloadable build isn't sandboxed and runs commands and scripts with Process, with your own user's permissions: a command can do anything you could do in Terminal. The Mac App Store build runs in the App Sandbox, which can't run shell commands: command actions show as unavailable there. It runs scripts from the Application Scripts folder through NSUserUnixTask, Apple's mechanism for this; macOS runs them outside the sandbox, so they too have your permissions, and LaunchGrid can't stop one once it has started.
Grid files and review. Actions are part of the layout, so undo, backups and grid files include them. Since a grid file can come from someone else, loading one (Load Grid File…, the welcome window, or double-clicking it in Finder) never runs anything. When it holds commands, scripts, links to other apps or files that run something when opened (an app, a .command or another executable, or any file opened with a terminal), a sheet first lists each with its name and full command, script, link or path, with Keep for Review, Remove Them (leaves those out) and Cancel Loading. Every action kept from a grid file shows an eye badge and, instead of running, opens in the editor with a note to check it; saving it there lets it run. LaunchGrid's own layout and its backups are never flagged. Saving a grid file leaves commands and scripts out unless you tick Include commands and scripts in the save panel: they're kept as placeholders with their names and icons, to fill in again.
~/Library/Application Support/LaunchGrid/grid.json. This is pretty-printed, versioned JSON written atomically about 0.5 s after each change; an earlier save is kept beside it as grid.json.bak, refreshed at the first save of each run and then at most every 10 minutes, so a change you regret doesn't overwrite it straight away. The first refresh of each day also keeps the backup it replaces as grid.backup-YYYY-MM-DD.json (the last three days), which Load Grid File… opens. An unreadable file (or one from a newer version) is moved aside, never overwritten. An unreadable one is replaced by the backup when that can be read, with an alert saying so; otherwise the welcome window says where it went. If it can't be moved, nothing is saved until you move it yourself. A file with only some entries that can't be read loads without them, and a copy of it as it was is kept beside it (grid.partial-….json), with an alert saying so. A save that fails when you quit asks before quitting. Apps excluded in the welcome window are saved before the layout is made.defaults read com.sglavoie.launchgrid.~/Library/Containers/com.sglavoie.launchgrid/Data/Library/, under Application Support/LaunchGrid/ and Preferences/com.sglavoie.launchgrid.plist.removedBundleIDs (by path for a copy that shares its bundle ID, like Xcode-beta), so scans and rebuilds don't re-add them; Choose Apps… or Add Missing Apps… brings them back.Two targets, each with a test target (LaunchGridCoreTests, LaunchGridTests):
LaunchGridCore: pure, unit-tested logic.
Model: value-type Grid, which makes undo a snapshot.GridOps: insert with overflow spill, move, group, reflow, sort.Reconciler: add new apps, drop deleted ones, follow moved ones, keep the removed list. An empty scan prunes missing apps only when at least one scan root was listed; apps on an unmounted volume or under a folder that is missing or can't be listed stay put.AppScanner: depth-limited, symlink-cycle-safe, skips bundle contents.Search, GridStore.LaunchpadImporter: reads a copy of the database and its write-ahead log; it handles Apple's multi-root DB, AppGrid's custom_path and manual_app_* IDs, and nested folder pages.LaunchGrid: the AppKit/SwiftUI app.
OverlayController: a non-activating NSPanel, so it takes keyboard focus without fighting cooperative activation. It shows on the screen under the pointer and handles key and scroll input.Interaction: one root DragGesture with arithmetic hit-testing, dwell timers for merge, reorder and edge-flip, and a live gap.SMAppService login item.String(localized:) or SwiftUI's LocalizedStringKey. Localizable.xcstrings holds their plural forms and, later, translations; scripts/bundle.sh compiles it into the bundle with xcstringstool, so swift build and the tests show the English keys.Development aid: LAUNCHGRID_DEBUG_SCRIPT="build:alpha;show;drag:0,3;merge:1,2;snap:x;quit" drives the UI with synthesized events and writes window snapshots to LAUNCHGRID_DEBUG_DIR. It only runs together with LAUNCHGRID_DATA_DIR, so it never edits your real layout; otherwise it's ignored with a note on stderr. It's left out of the Mac App Store build. LAUNCHGRID_DATA_DIR points the app at a scratch layout and the com.sglavoie.launchgrid.scratch settings domain, and lets it run beside the installed copy (which keeps the global shortcut). See Sources/LaunchGrid/DebugScript.swift.
.lmy import, whose format is unverified. .agrid files load through the SQLite importer.MIT; see LICENSE.
{query}gh launchgridlaunchgrid{query}| Right-click | Item: Open, Show in Finder, Edit Action (actions), Rename, Move to Page, Group, Remove. Background: page and sort actions, New Action. With the keyboard, ⌃Return opens the focused item's menu and ⇧⌃Return the ⋯ menu |
LAUNCHGRID_QUERY$LAUNCHGRID_QUERY{query}