A terminal UI, macOS menu bar app, and HTTP API for monitoring all your coding agents — Claude Code, Cursor, pi, and OpenCode — from a single place. No lock-in, no server, purely observational.
Inspired by lazygit, lazyworktree, and pixel-agents.
Unlike other tools, lazyagent doesn't replace your workflow — it watches it. Launch agents wherever you want (terminal, IDE, desktop app), lazyagent just observes. No lock-in, no server, no account required.
⭐ If lazyagent is useful to you, consider starring the repo — it helps others discover it!
lazyagent watches session data from coding agents to determine what each session is doing. No modifications to any agent are needed — it's purely observational.
Supported agents:
- Claude Code CLI — reads JSONL from
~/.claude/projects/*/ - Claude Code Desktop — same JSONL files, enriched with session metadata (title, permissions) from
~/Library/Application Support/Claude/claude-code-sessions/ - Cursor — reads SQLite from
~/Library/Application Support/Cursor/User/globalStorage/state.vscdb - pi coding agent — reads JSONL from
~/.pi/agent/sessions/*/ - OpenCode — reads SQLite from
~/.local/share/opencode/opencode.db
Use --agent claude, --agent pi, --agent opencode, --agent cursor, or --agent all (default) to control which agents are monitored. Agents can also be enabled/disabled in the config file. Pi sessions are marked with a π prefix, Cursor with C, OpenCode with O, and Desktop sessions with a D prefix in the session list.
From the JSONL stream it detects activity states with color-coded labels:
- idle — Session file exists but no recent activity
- waiting — Claude responded, waiting for your input (with 10s grace period to avoid false positives)
- thinking — Claude is generating a response
- compacting — Context compaction in progress
- reading / writing / running / searching / browsing / spawning — Tool-specific activities
It also surfaces:
| Info | Source |
|---|---|
| Working directory | JSONL |
| Git branch | JSONL |
| Claude version | JSONL |
| Model used | JSONL |
| Is git worktree | git rev-parse |
| Main repo path (if worktree) | git worktree |
| Message count (user/assistant) | JSONL |
| Token usage & estimated cost | JSONL |
| Activity sparkline (last N minutes) | JSONL |
| Last file written | JSONL |
| Recent conversation (last 5 messages) | JSONL |
| Last 20 tools used | JSONL |
| Last activity timestamp | JSONL |
| Session source (CLI / Desktop) | Desktop metadata |
| Desktop session title | Desktop metadata |
| Permission mode (Desktop) | Desktop metadata |
| Custom session name | ~/.config/lazyagent/session-names.json |
lazyagent ships as a single binary with three interfaces:
| TUI | macOS Menu Bar | HTTP API | |
|---|---|---|---|
| Interface | Terminal (bubbletea) | Native menu bar panel (Wails v3 + Svelte 5) | REST + SSE |
| Launch | lazyagent |
lazyagent --tray |
lazyagent --api |
| Dock icon | N/A | Hidden (accessory) | N/A |
| Sparkline | Unicode braille characters | SVG area chart | JSON data |
| Theme | Terminal colors | Catppuccin Mocha (Tailwind 4) | N/A |
All three share internal/core/ — session discovery, file watcher, activity state machine, cost estimation, and config. You can combine them freely: lazyagent --tui --tray --api.
brew tap illegalstudio/tap
brew install lazyagentgo install github.com/illegalstudio/lazyagent@latestgit clone https://github.com/illegalstudio/lazyagent
cd lazyagent
# TUI only (no Wails/Node.js needed)
make tui
# Full build with menu bar app (requires Node.js for frontend)
make install # npm install (first time only)
make buildOn first launch, macOS may block the binary. Go to System Settings → Privacy & Security, scroll down and click Allow Anyway, then run it again.
lazyagent Launch the terminal UI (monitors all agents)
lazyagent --agent claude Monitor only Claude Code sessions
lazyagent --agent pi Monitor only pi coding agent sessions
lazyagent --agent opencode Monitor only OpenCode sessions
lazyagent --agent cursor Monitor only Cursor sessions
lazyagent --agent all Monitor all agents (default)
lazyagent --api Start the HTTP API (http://127.0.0.1:7421)
lazyagent --api --host :8080 Start the HTTP API on a custom address
lazyagent --tui --api Launch TUI + API server
lazyagent --tray Launch as macOS menu bar app (detaches)
lazyagent --tray --api Launch tray + API server (foreground)
lazyagent --tui --tray --api Launch everything
lazyagent --help Show help
| Key | Action |
|---|---|
↑ / k |
Move up / scroll up (detail) |
↓ / j |
Move down / scroll down (detail) |
tab |
Switch focus between panels |
+ / - |
Adjust time window (±10 minutes) |
f |
Cycle activity filter |
/ |
Search sessions by project path |
o |
Open session CWD in editor (see below) |
r |
Rename session (empty name resets) |
q / ctrl+c |
Quit |
lazyagent --tray
The tray process detaches automatically — your terminal returns immediately. The app lives in your menu bar with no Dock icon. Click the tray icon to toggle the panel.
| Key | Action |
|---|---|
↑ / k |
Move up |
↓ / j |
Move down |
+ / - |
Adjust time window (±10 minutes) |
f |
Cycle activity filter |
/ |
Search sessions |
r |
Rename session (empty name resets) |
esc |
Close detail / dismiss search |
- Show Panel — open the session panel
- Refresh Now — force reload all sessions
- Quit — exit the app
lazyagent --api
Starts a read-only HTTP API server on http://127.0.0.1:7421 (default port, with automatic fallback if busy).
| Endpoint | Description |
|---|---|
GET /api |
Interactive playground (open in browser) |
GET /api/sessions |
List visible sessions (?search=, ?filter=) |
GET /api/sessions/{id} |
Full session detail |
PUT /api/sessions/{id}/name |
Rename session ({"name": "..."}, empty resets) |
DELETE /api/sessions/{id}/name |
Remove custom name |
GET /api/stats |
Summary stats (total, active, window) |
GET /api/config |
Current configuration |
GET /api/events |
SSE stream for real-time updates |
To expose on the network (e.g. for a mobile app):
lazyagent --api --host 0.0.0.0:7421Full API documentation: docs/API.md
Pressing o (TUI) or the Open button (app) opens the selected session's working directory in your editor.
Cursor sessions automatically open in Cursor IDE (if the cursor CLI is installed). If not installed, the standard editor flow below is used.
| Configuration | Behavior |
|---|---|
Both $VISUAL and $EDITOR set |
A picker popup asks which one to use (TUI only) |
Only $VISUAL set |
Opens directly as GUI editor |
Only $EDITOR set |
Opens directly as TUI editor (suspends the TUI) |
| Neither set | Shows a hint to configure them |
# Example: add to ~/.zshrc or ~/.bashrc
export VISUAL="code" # GUI editor (VS Code, Cursor, Zed, …)
export EDITOR="nvim" # TUI editor (vim, nvim, nano, …)lazyagent reads ~/.config/lazyagent/config.json (created automatically with defaults on first run):
{
"window_minutes": 30,
"default_filter": "",
"editor": "",
"launch_at_login": false,
"notifications": false,
"notify_after_sec": 30,
"agents": {
"claude": true,
"cursor": true,
"opencode": true,
"pi": true
}
}| Field | Default | Description |
|---|---|---|
window_minutes |
30 |
Time window for session visibility (minutes) |
default_filter |
"" |
Default activity filter (empty = show all) |
editor |
"" |
Override for $VISUAL/$EDITOR |
launch_at_login |
false |
Auto-start the menu bar app at login |
notifications |
false |
macOS notifications when a session needs input |
notify_after_sec |
30 |
Seconds before triggering a "waiting" notification |
agents |
all true |
Enable/disable individual agent providers |
lazyagent/
├── main.go # Entry point: dispatches --tui / --tray / --api / --agent
├── internal/
│ ├── core/ # Shared: watcher, activity, session, config, helpers
│ │ └── provider.go # SessionProvider interface + Multi/Live/Pi/OpenCode/Cursor providers
│ ├── model/ # Shared types (Session, ToolCall, etc.)
│ ├── claude/ # Claude Code JSONL parsing, desktop metadata, session discovery
│ ├── cursor/ # Cursor IDE session discovery from state.vscdb
│ ├── pi/ # pi coding agent JSONL parsing, session discovery
│ ├── opencode/ # OpenCode SQLite parsing, session discovery
│ ├── api/ # HTTP API server (REST + SSE)
│ ├── ui/ # TUI rendering (bubbletea + lipgloss)
│ ├── tray/ # macOS menu bar app (Wails v3, build-tagged)
│ └── assets/ # Embedded frontend dist (go:embed)
├── frontend/ # Svelte 5 + Tailwind 4 (menu bar app UI)
│ ├── src/
│ │ ├── App.svelte
│ │ ├── lib/ # SessionList, SessionDetail, Sparkline, ActivityBadge
│ │ └── bindings/ # Auto-generated Wails TypeScript bindings
│ └── app.css # Tailwind 4 @theme (Catppuccin Mocha)
├── docs/ # Documentation
│ └── API.md # Full HTTP API reference
└── Makefile
# Install frontend deps (first time)
make install
# Full build (TUI + tray)
make build
# Build TUI only (no Wails/Node.js needed)
make tui
# Quick dev cycle (rebuild + run tray)
make dev
# Clean all artifacts
make clean- Go 1.25+
- Node.js 18+ (for frontend build)
- macOS (for the menu bar app — TUI works on any platform)
- Discover all Claude Code sessions from
~/.claude/projects/ - Parse JSONL to determine session status
- Detect worktrees
- Show tool history
- FSEvents-based file watcher with debouncing
- Fallback 30s polling
- Conversation preview in detail panel (last 5 messages, User/AI labels)
- Last file written with age
- Filter sessions by activity type
- Search sessions by project path
- Time window control (show last N minutes)
- Color-coded activity states with grace periods
- Memory-efficient single-pass JSONL parsing
- Activity sparkline graph in session list
- Token usage and cost estimation in detail panel
- Animated braille spinner for active sessions
-
okey to open session CWD in editor - Rename sessions with persistent custom names (
rkey) - Display file diff for last written file
- Core library extraction (
internal/core/) - Shared config system (
~/.config/lazyagent/config.json) - Wails v3 + Svelte 5 + Tailwind 4 frontend
- System tray with attached panel (frameless, translucent, floating)
- Real-time session updates via FSEvents + event push
- SVG sparkline, activity badges, conversation preview
- Keyboard shortcuts (j/k, /, f, +/-, r, esc)
- Open in editor from detail panel
- Dynamic tray icon (active session count)
- macOS notifications when session needs input
- Launch at Login
- Code signing & notarization
- DMG distribution
- Homebrew cask
- REST API server (
--apiflag) - Session list, detail, stats, config endpoints
- Server-Sent Events (SSE) for real-time push updates
- Interactive API playground (
/apiin browser) - Default port with automatic fallback (7421–7431)
- Custom bind address (
--host) - Combinable with TUI and tray (
--tui --tray --api) - Session rename endpoints (
PUT/DELETE /api/sessions/{id}/name)
- pi coding agent session discovery (
~/.pi/agent/sessions/) - Pi JSONL parser (tree-structured format → shared Session struct)
-
--agentflag (claude,pi,all) - MultiProvider merging sessions from multiple agents
- Agent type indicator (π prefix in list, Agent row in detail)
- Pi tool name normalization (snake_case → PascalCase)
- Multi-directory file watcher
- Cost estimation for Gemini and GPT model families
- Claude Code Desktop support (title, permissions, source badge)
- Shared session types extracted to
internal/model
- OpenCode session discovery from SQLite (
~/.local/share/opencode/opencode.db) -
--agent opencodeflag - Polling-based refresh (5s interval, no file watcher needed)
- Tool name normalization and activity mapping
- Subagent detection via
parent_id
- Cursor session discovery from
state.vscdb(composerData + bubbleId entries) -
--agent cursorflag - WAL-based cache invalidation for real-time updates
- CWD inference from file URIs when workspace URI is unavailable
- Cursor tool name normalization (Read_file_v2, Glob_file_search, etc.)
- Open in Cursor IDE (with fallback if CLI not installed)
- Per-agent enable/disable in config (
agentsmap)
- Outbound webhooks on status changes
- Multi-machine support via shared config / remote API
- TUI actions: kill session, attach terminal
- Session history browser (browse past conversations)


