Monitor progress of and switch between lemons (go on... say 'LLMs' three times fast) running in the terminal.
The inbox can live in a pane that follows you across every window and session switch, so it is ambient rather than something you summon:
lemonaid tmux scratch --follow # left or top, from config
lemonaid tmux scratch --flip # move it to the other edgeOn the left, above, each session is a card: name, then time, cwd and branch,
then the message wrapped over as many lines as the pane can spare. With
brief_status on, a card also shows its lemon's brief:
a red headline and what it needs from you when alert, yellow when blocked,
green when merge, purple when approve, brown when review, blue when done,
teal while running. A brief that sets no status shows its lemon's own state:
active mid-turn, dimmed while idle, and red deaf or dead when a message to
it would not be read (brief status).
Across the top, it has room for columns instead, one row per session, with
alert rows red, blocked rows amber, merge rows green, approve rows purple,
review rows brown, done rows blue, and running rows teal:
The inbox's title turns teal while it has keyboard focus, and in the top strip
the column header turns the unread marker's colour while something is waiting
for you. prefix+l toggles focus between the inbox and your work; q parks it
until you want it back.
To see it with invented sessions before wiring up your own:
uv run scripts/demo-inbox.py # a throwaway tmux server, own inbox
uv run scripts/demo-inbox.py --killThe screenshots here come from that demo:
uv run scripts/demo-inbox.py --no-attach (add --top for the strip), then
uv run scripts/demo-screenshot.py docs/images/inbox-left.png.
Full setup, keybindings, and behaviour: docs/tmux.md.
Lemonaid has two parts: hooks that fire when your lemons need attention, and a TUI (lma) that shows what's going on and lets you jump to sessions.
- You add hooks to Claude Code, Codex CLI, and/or OpenCode (see Integrations below)
- When a session stops or needs input, the hook writes a notification to a local SQLite database
- The
lmaTUI displays active notifications, watches transcripts for live activity, and auto-archives sessions when they end - When you select an active session, you are taken directly to that pane/tab in
tmux, WezTerm or cmux - Over time, archived sessions accumulate into a searchable session history β press
hto browse past sessions across all projects and resume them
The TUI doesn't need to be running for notifications to arrive (hooks write directly to the DB), but it does need to run for live activity updates and automatic archiving.
-
Restart a lemon:
lemonaid lemon restart <lemon>resumes one live Claude or dedicated Codex conversation in its own tmux pane after an exact-PID stop, with--dry-runand saved operation status. -
Jump from a link:
lemonaid go <Lemon-ID | channel>switches to a lemon's tmux pane or cmux surface, and--linkprints a clickable link. macOS URL-handler setup is documented. -
PR numbers in the inbox: A session shows its PR numbers beside its name, from its brief or an optional per-root branch lookup hook. When a URL is available, modifier-click opens the PR.
-
Context use in the inbox: Opt in to see how much context each Claude and Codex lemon has used, as a percentage of a threshold you set per backend or model, coloured from blue to red at the threshold
-
Stall check: A card says "stuck 45m: reviewer's move on #238" when the lemon that owes the next move on a PR has sat idle past
stall_minutes;lemon doctor --stallslists the same. -
Subscription usage:
lemonaid usageshows how much of each Claude and Codex limit window is used against its pace, and--watchblocks until usage crosses a step or is on track to run out before the reset. Thresholds are configurable. -
Vault paths in the terminal:
lemonaid terminal vault-links iterm2(orwezterm) installs a rule that opens a printed.mdpath under a[brief] vaultsroot in Obsidian when clicked, spaces in folder names included -
Notification inbox: Track which Claude Code, Codex CLI, OpenClaw, and OpenCode sessions need your attention, and what they're doing as they do it
-
Project names within a root: An optional per-root hook maps working directories to project labels in the inbox
-
Quiet sessions:
Hhides or unhides the selected lemon through its brief, and/search includes hidden lemons. A lemon whose brief saysHidden: yes(lemonaid brief hide), such as a reviewer, stays out of the default inbox until you switch to them, select or pin them, or their brief enters a specially ranked status -
Terminal integration: Hit enter to jump directly to the waiting session's pane (supports
tmux, WezTerm and cmux). If the session has since died, it is resumed in a new pane in the same directory rather than the jump failing -
Session history & resume: Browse archived sessions across all projects, filter by name/cwd/branch, and resume directly or copy the command
-
Integrated search: Press
/to filter inbox and archive sessions as you type, including attached brief names; inbox rows keep their formatting and fill the list first, with archive matches below a divider when room remains -
Places: Spin up a directory and its session in one command, and retire a single-purpose tmux workspace with optional directory cleanup in one command, while refusing hybrid workspaces. What "spin up a directory" means is a shell command you configure per repo, so worktrees (or whatever else you use) stay out of lemonaid's model
-
Briefs:
bon a session shows its brief name,Brief-ID, parent,Status:, what it needs from you, and the rest of## Nowbeside the lemon or in a tmux popup, without switching to it, with the live state of any PR the brief names when[brief] pr_stateis configured. The name (SkullHeninSkullHen.mc-tars) is bold in brief IDs and children;[tui] brief_names_in_inbox = truealso shows it after the session name in the inbox.lemonaid brief showprints the same from anywhere, including a worker's## Executive Summary of Results. A brief keeps its metadata (Brief-ID, status, parent, who asked for it, who edited it) in YAML frontmatter; older header-line briefs convert on their first edit. Questions a brief explains under## Questionsshow under what the lemon needs, andaanswers one orDasks for more detail, sent to the lemon's inbox -
Harness handoff: Move an attached brief from Claude to Codex, or back, with
lemonaid brief handoff --to <harness>. A handoff to the lemon's own harness gives it a fresh session in the same pane, and so does/clearin a Claude lemon. In tmux, the target replaces the old harness in the same pane after readiness; a failed cutover resumes the old session there. After Ctrl-Z returns control to an interactive shell, run the same command there; Lemonaid finds the stopped harness on the controlling TTY, waits for its handoff brief, and starts the replacement in that terminal. It refuses to guess when TTY matches are ambiguous. Without a live tmux pane, pass--brief FILEto select an attached source explicitly and use the manually staged status/start-command flow. The old session stays available by its original ID. -
Lemon messages: Each brief carries a stable ID for its file inbox. Send Markdown by ID, channel, or brief name with
lemonaid tell; receive one withlemonaid inbox next --selfor wait withlemonaid inbox watch --self. Codex lemons get messages queued into their threads by a self-starting delivery service; an optional Stop hook keeps each Claude lemon's waiter armed -
Starting lemons from config:
lemonaid lemon start SESSION:WINDOWruns a preset's lemon command in another window of a session, with a brief, parent, and name, and never over a live process. Codex starts past its trust and update prompts. -
Child briefs from templates:
lemonaid brief new --childwrites a brief for a lemon not started yet, with its parent filled in, ready forplace open --brieforlemon start --brief.--template reviewwrites a PR reviewer's brief with its waiters; your own templates go in~/.lemons/brief-templates/ -
Starting your HQ: A guide to setting up a pinned lemon that watches your other lemons: hooks, adopting running lemons, its waiters, recovering after a restart, and a starter prompt
-
Parent links: Record which lemon handed another its work, by Lemon-ID, with
place open --parent selforlemonaid lemon parent.lemon childrenlists a parent's children with their brief status, andtell --parentandtell --childmessage along the links -
The grove (beta):
Spaceinlmaopens a map of your lemons where each group is a block and each session a tree, and nothing moves once placed. A digit zooms into a block, a letter jumps to a tree's lemon (2c), and/finds one by Brief-ID.lemonaid grove show --jsonlets a lemon read the layout andgrove moverearrange it -
Groups: Name a set of lemons with
lemonaid group, a lemon and its descendants at once with--tree, or a new child withplace open --group. A lemon can be in several groups, and each member brief carries aGroups:line so its groups follow it to another machine.lmadraws groups in a persistent manual order, and edits groups in place:Shift+β/βmoves a group,Ggroups a lemon with its descendants,+and-add and remove, andCsaves a group's color -
One watcher per lemon:
lemonaid watch --selfreads the brief and gathers its subscriptions, PRs, docs, children and inbox messages into one wake. A detached push scout delivers each batch into the lemon's session: through the session socket for Claude, and withcodex queuefor Codex. -
Watches:
lemonaid watch doc,watch pr,watch file, andwatch briefs --childrenwait, at no token cost, for a Relay Comment on a document, activity on a GitHub PR, a changed file, or a child enteringmerge,done, or statuses selected with--to, then wake the lemon: a Claude background task exits or a Codex thread gets a queued message. OpenClaw sessions get an agent turn for document comments. Missing watched documents and paths can suggest nearby replacements for the lemon to confirm; subscriptions stay unchanged. Watches automatically record restartable commands in an attached brief. A lemon's own edits to a document it watches, by any tool, and its own pushes don't wake it (lemonaid hooks install, for Claude Code and Codex). PR comment watches include outdated and resolved threads by default, with optional filters for quieter waits. Underwatch --self, each PR wakes a lemon only for the events its role (author, reviewer or parent) needs, and a GitHub outage is reported once, after a debounce. Addwatch pr --cito wake when CI finishes, passing or failing.lemonaid watch stop --selfstops the caller's own waiters, one or all, and only those -
Event notes: Add your own instructions to one kind of watcher event, such as a child going
done, with a file in~/.lemons/event-notes/. Lemonaid appends it to every event of that kind it delivers -
Skills:
lemonaid skills installinstallsbrief,watch-doc,watch-pr, andwatch-briefsskills for Claude Code and Codex, with your own additions appended from~/.lemons/skills/<name>/overlay.md -
Brief status cards: Opt in with
[tui] brief_status = trueto color cards by attached brief status, show what a lemon needs from you or is waiting on, and how long it has held its status -
Brief edit verbs:
brief sectionedits any heading,brief bulletchanges a bullet anywhere, andbrief prandbrief docmaintain watched tables.brief migratepromotes legacy Next, PRs, Docs and Done headings out of Now, andbrief waiteredits## Watching;brief checkfinds what a hand edit broke, and the Claude Stop hook runs it -
Auto-read: Regexes in
[inbox] auto_readleave a session read when its turn ends with a matching final message, so routine turns don't ask for attention -
Arrangers:
[inbox] arrangenames a program, in any language, that reorderslma's list and chooses what folds.lmakeeps it running and falls back to its own order when it fails, andlemonaid inbox arrange checktries one against your inbox -
Restore (
tmux):lemonaid restore tmuxrebuilds the tmux sessions your lemons were in after a crash or restart, starts each lemon with a prompt to rearm the waiters its brief lists, and reports which ones came back working -
Notes: Keep a Markdown file of your own in view under the sessions in the sidebar, such as tmux key hints while you learn them.
Nhides it -
Pins: Hold a session at the top of the list, in an order you choose
-
Snooze: Hold a session that needs attention "but not yet" until a time you pick, with a snoozed list so nothing goes missing. A lemon can snooze itself with
lemonaid inbox snooze --self -
Undo: Reverse an accidental archive, mark-read, snooze, or rename - multi-level, with a toast naming what changed
-
Bootstrap:
lemonaid claude bootstrapimports historical Claude sessions from before lemonaid was installed into the archive -
Scratch pane size autosave: Opt in to save settled border and keyboard resizes in follow mode;
Ctrl+sremains available to save explicitly -
Always-visible sidebar (
tmux): Follow mode keeps the inbox in view across every window and session switch, on the left or across the top. Sessions render as cards when the pane is too narrow for columns. Without follow mode it is still a scratch pane you toggle with a keybinding, with no startup delay -
Brief beside the lemon (
tmux): When the scratch pane follows on the left,breplaces the inbox with the selected lemon's brief and keeps keyboard focus there.prefix+bopens the brief from the lemon and focuses the scratch pane; switching away restores the inbox -
Auto-refresh TUI: See new notifications appear without losing your place
- Claude statusline: Colorful statusline showing time, elapsed, git branch, context %, vim mode
- Lemon presets and session shapes: Choose a window layout independently of a lemon's harness and model, append startup flags, and inspect the resolved launch before starting it
tmuxsession shapes: Spin up new named workspaces with a predefined window layout;tmux newstill reads the older templatestmuxwindow status formatting: An optionaltmuxintegration to keep your status bar sane
uv tool install lemonaid-inboxThe package on PyPI is lemonaid-inbox, because lemonaid there is an
unrelated project. The commands are still lemonaid and lma.
After installing or upgrading, install lemonaid's skills for Claude Code and Codex:
lemonaid skills installlma also refreshes skills you've installed when it starts after an upgrade, but a fresh
install needs the command once. See Skills.
To run from a checkout instead:
git clone https://github.com/petergaultney/lemonaid.git
cd lemonaid
# Install globally with uv, then install the skills
uv tool install --editable .
lemonaid skills install
# For development
uv sync
uv run pre-commit installAn install made before the rename is a uv tool named
lemonaid, which holds the same commands. Remove it once with
uv tool uninstall lemonaid before either install above.
On macOS, check the tmux server setup before using follow mode, especially the file-descriptor limit and window options.
Before running or extending the test suite, read docs/testing.md, especially its watcher-isolation safety invariant. For this repo's multi-lemon merge and live-install workflow, see docs/development.md.
Add hooks to ~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "lemonaid claude submit" }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "lemonaid claude notify" }] }],
"PermissionRequest": [{ "matcher": "AskUserQuestion", "hooks": [{ "type": "command", "command": "lemonaid claude notify" }] }],
"Notification": [{ "matcher": "permission_prompt", "hooks": [{ "type": "command", "command": "lemonaid claude notify" }] }]
}
}Features: sessions appear in the inbox the moment a prompt is submitted (UserPromptSubmit), questions asked mid-turn with AskUserQuestion notify you (PermissionRequest), auto-dismiss via transcript watching, live activity updates, binary patch for faster notifications.
Full documentation: docs/claude.md | Binary patch
Add to ~/.codex/config.toml at the very top (before any [table] headers):
notify = ["lemonaid", "codex", "notify"]Features: auto-dismiss via session watching, live activity updates.
Full documentation: docs/codex.md
Register from within an OpenClaw TUI session:
!lemonaid openclaw register
Features: turn-complete detection, live activity updates, auto-dismiss on user input.
Full documentation: docs/openclaw.md
Add this plugin at ~/.config/opencode/plugins/lemonaid.js (or .opencode/plugins/lemonaid.js in a project):
export const LemonaidPlugin = async ({ $ }) => ({
event: async ({ event }) => {
if (event.type === "session.idle" || event.type === "permission.asked") {
await $`lemonaid opencode notify ${JSON.stringify(event)}`
}
},
})Features: idle/permission notifications via plugin hooks, auto-dismiss via session DB watching, live activity updates.
Full documentation: docs/opencode.md
tmux(3.0 or later; follow mode needs 3.6): See docs/tmux.md for pane switching, back navigation, session shapes, and window colors- WezTerm: See docs/wezterm.md for workspace/pane switching setup
- cmux: Switching to a session's workspace and surface, and resuming a dead one, needs no cmux configuration; see docs/cmux.md for the hooks and for running
lmain the Dock
# Open the inbox TUI
lma
# Or via the full CLI
lemonaid inbox
# List notifications (non-interactive)
lemonaid inbox listThe inbox and the scratch sidebar list sessions in the same order:
- Pinned sessions, in the order you put them.
- Sessions whose attached brief says
alert: your move, and harm grows while it waits. - Sessions whose brief says
blocked: a decision, answer, or review for you. - Sessions whose brief says
running: a lemon minding a pipeline or other long process. - Sessions whose brief says
merge: only your merge is left. - Sessions whose brief says
approve: a reviewer recommends approving a teammate's PR, and only your approval is left. - Sessions whose brief says
review: a teammate's approving review comes before your merge. - Sessions whose brief says
done. - Every other unread session.
- Every other read session: a brief without a status, or no brief.
With [tui] mid_turn_working on, a read session that is
mid-turn is drawn as active until the turn ends, whatever its brief says, unless
it says running. It keeps the place its brief gives it.
With [tui] fold_statuses set,
read sessions of those statuses fold into one line at the bottom, which w opens.
Within each group other than the pins, unread comes first, then newest first.
| Key | Action |
|---|---|
Enter |
Switch to the session's pane |
1-9, 0 |
Switch to that row |
u |
Jump to the oldest unread session |
M / Alt+m |
Mark as read / unread |
A |
Archive |
s / S |
Snooze / list snoozed |
P |
Pin below the other pins, or unpin; Shift+β/β moves a pin |
b |
Show the session's brief |
Z |
Undo the last inbox change |
h |
Session history (Enter resumes, c copies the resume command) |
/ |
Search inbox and archived sessions |
F |
Move the scratch pane between top and left |
? |
Show the key reference |
q / Escape |
Quit |
The full list, including rename, history filtering, and the brief view's own keys, is in docs/keybindings.md, along with how to rebind them.
For JSON output and programmatic access (useful for lemons), see docs/for-lemons.md
β or run lemonaid for-lemons, which prints the same guide from any install.
Config file: ~/.config/lemonaid/config.toml β see docs/config.md for the full reference.
- docs/keybindings.md - Customize TUI keybindings
- docs/tmux.md - tmux integration and session shapes
- docs/wezterm.md - WezTerm integration
- docs/vault-links.md - Clickable vault paths in iTerm2 and WezTerm
- docs/cmux.md - cmux integration
- inbox: SQLite-backed session status storage with Textual TUI
- claude: Claude Code hook integration with transcript watching
- codex: Codex CLI hook integration with session watching
- openclaw: OpenClaw integration with turn-complete detection
- opencode: OpenCode integration with plugin events and live activity watching
- brief and messages: attached briefs, their popup and sidebar views, and the per-lemon file inboxes behind
lemonaid tell - places: per-repo hooks that create and remove directories, and the tmux sessions opened in them
- tmux / wezterm: pane switching, the scratch pane and follow mode, session shapes
- cmux: switching to a session's workspace and surface

