⚠️ This plugin is entirely vibe-coded. Every line of it — the QML, the Bash, the JavaScript, the tests and this README — was written by an AI coding agent (Claude Code) from prompts, not hand-authored. It is tested and it works, but read the code before you enable it: Omarchy plugins run unsandboxed insideomarchy-shell.
A project menu for the Omarchy shell (Quickshell).
A keybinding opens an overlay listing the projects in your working folders; pick
one and it opens (or re-attaches) a per-project tmux session built from the
layout you configure. By default:
- window
git→lazygitin the project - window
edit→ your editor (nvimby default) in the project - window
code→ an AI pane (defaultclaude --dangerously-skip-permissions) on top taking 75% of the height, and a companion pane (cliamp) below. The separator is horizontal (stacked panes).
For each project the menu shows an ecosystem icon, git status
(branch · ahead/behind · dirty files) and a ● when a tmux session is already
live (picking it just re-attaches). Order is: favourites → live sessions →
frecency (most used / most recent first). Optionally a preview pane on the right
with git log + the highlighted project's README.
| Key | Action |
|---|---|
↑ / ↓, PgUp / PgDn |
Move the selection |
Enter |
Open / re-attach the session |
| type | Filter (fuzzy) |
Tab / Shift+Tab |
Switch the AI preset (when aiPresets is set) |
Ctrl+P |
Toggle the preview pane |
Ctrl+K |
Kill the selected project's tmux session |
Ctrl+R |
Kill and re-open the session |
Ctrl+D |
Toggle favourite |
Esc |
Clear the filter, or close |
If you type a name that matches no project, a + Create «…» row appears that
creates <projectRoots[0]>/<name> (mkdir + git init) and opens the session.
- Omarchy 4 (Quattro) with the
omarchy-shellplugin system. tmux,lazygitonPATH.- Whatever AI command you configure (
claudeby default). - Optional:
cliamp(or whichever companion you pick),jq(for frecency and for the script to read the config), a Nerd Font (Omarchy already ships JetBrainsMono Nerd Font).
omarchy plugin add https://github.com/Cache21/omarchy-project-launcher --enableIt is cloned to ~/.config/omarchy/plugins/io.github.cache21.project-launcher/
and enabled. Then add the keybinding (a plugin can't touch your Hyprland config).
Either:
A. Automatic (adds SUPER + ALT + P to ~/.config/hypr/bindings.lua):
~/.config/omarchy/plugins/io.github.cache21.project-launcher/install.shB. Manual — paste this into ~/.config/hypr/bindings.lua:
o.bind("SUPER + ALT + P", "Project launcher",
"omarchy-shell shell toggle io.github.cache21.project-launcher '{}'")then reload with hyprctl reload.
Read from ~/.config/omarchy-project-launcher/config.json (created on first run
from config.default.json). Hot-reloaded on save. See
config.example.jsonc for the commented version.
| Key | Default | Description |
|---|---|---|
projectRoots |
["~/Projects"] |
Root folders to scan for projects. It's an array: add as many as you want, e.g. ["~/Projects", "~/eclipse-workspace", "~/work"]. Supports ~ and $VARS. |
scanDepth |
1 |
Subdirectory depth per root (2 surfaces sub-apps like mono/backend). |
onlyGitRepos |
false |
List only folders that are git repos. |
ignore |
["node_modules", ".git", ".*"] |
Name globs to exclude. |
aiCommand |
"claude --dangerously-skip-permissions" |
AI command. Substitutes {{ai}} in the layout. |
companionCommand |
"cliamp" |
Companion command. Substitutes {{companion}}. |
editorCommand |
"nvim" |
Editor. Substitutes {{editor}}. "" removes the edit window. |
aiPaneHeightPercent |
75 |
Substitutes {{companionSize}} with $(100-this)% (10–90). |
startWindow |
"code" |
Window focused on attach (any layout name). |
reuseExistingSession |
true |
If the session already exists, re-attach instead of creating another. |
terminalAppId |
"dev-session" |
Terminal --app-id (for Hyprland window rules). See note below. |
layout |
see below | Windows/panes of the tmux session. |
aiPresets |
{} |
{ name: command } for the Tab selector in the menu. {} = hidden. |
showPreview |
true |
Preview pane on the right (Ctrl+P toggles it; auto-hidden on narrow screens). |
createGitInit |
true |
The + Create action runs git init in the new folder. |
remainOnExit |
false |
If a pane's command dies, keep the pane showing its output. |
favorites |
[] |
Projects pinned to the top (name or path). Also Ctrl+D in the menu. |
colorIcons |
true |
Colour each project's icon by language (devicon palette). |
Note on
terminalAppId: it is passed as--app-idtoxdg-terminal-exec. foot, ghostty and alacritty honour it (Wayland app-id). kitty ignores it and keeps itsclass=kitty; with kitty, match ontitlein the window rule, or change your default terminal in~/.config/xdg-terminals.list.
layout is a list of windows. Each has name and panes: the first pane creates
the window; the rest split it ("v" = horizontal / stacked separator, "h" =
vertical / side by side) with an optional size ("25%" or a line/column count).
Placeholders: {{ai}}, {{editor}}, {{companion}}, {{companionSize}}. A pane
with an empty command is dropped; a window with no panes is dropped (so
editorCommand: "" removes the edit window).
A .project-session.json (plain JSON) at a project's root overrides any global
config key for that project (deep object merge; arrays such as layout are
replaced wholesale). E.g. ~/Projects/my-app/.project-session.json:
{ "aiPaneHeightPercent": 60,
"layout": [
{ "name": "git", "panes": [ { "command": "lazygit" } ] },
{ "name": "code", "panes": [ { "command": "{{ai}}" }, { "command": "{{companion}}", "split": "v", "size": "{{companionSize}}" } ] },
{ "name": "web", "panes": [ { "command": "npm run dev" } ] },
{ "name": "db", "panes": [ { "command": "npx prisma studio" } ] } ] }"aiPresets": {
"claude": "claude --dangerously-skip-permissions",
"codex": "codex",
"aider": "aider",
"shell": ""
}In the menu the header shows ▸ <preset>; Tab / Shift+Tab switches, Enter
launches with it, and the last choice is remembered (state.json).
The script does all the tmux work and runs on its own:
project-session ~/Projects/my-project # build/attach the session
project-session create my-app # mkdir + git init + open
project-session kill my-project # kill the tmux session
project-session preview ~/Projects/x # git log + README (used by the preview pane)
project-session --pick # picker (omarchy-menu-select / fzf) + open
project-session list # TSV of projects (consumed by the QML menu)
project-session doctor # deps + config + resolved layoutIt lives at
~/.config/omarchy/plugins/io.github.cache21.project-launcher/bin/project-session
(symlink it into a PATH dir if you like).
The script is the only thing that writes state, under
~/.local/state/omarchy-project-launcher/: frecency.json, favorites.json,
state.json (last AI preset).
node tests/model.test.js # pure logic in Model.js
qmllint -I "$OMARCHY_PATH/shell" Menu.qml
omarchy plugin validate .
omarchy-shell shell rescanPlugins # reload after changesmanifest.json— pluginkind: ["menu"], entry pointMenu.qml.Menu.qml— layer-shell overlay (PanelWindow+WlrLayershell): list + search + preview + preset selector. Scans viabin/project-session list, queriestmux list-sessionsandgit status, orders withModel.sortEntries. Only reads the state files; shells out to the script's subcommands for everything else.Model.js— pure, testable logic (parsing, ecosystem detection, git, frecency, fuzzy,resolveLayout, presets, the "create" row). Imported from QML and runs under node (tests/model.test.js).bin/project-session— resolves the config (+ per-project override), builds the layout withjq, creates the tmux session and opens it withomarchy-launch-tui(or$TMUX→switch-client, or$TERMINAL). The only writer of state.
MIT — see LICENSE. Not affiliated with the Claude, cliamp, lazygit or tmux projects.
