Activity Monitor for your Gradle daemons — see what's building right now, and what built recently.
Daemonitor is a local desktop app that shows the Gradle activity happening on your machine: which daemons, wrappers, and test workers are running, how much memory and CPU they're using, the latest daemon-log lines, and a searchable history of past builds — including which AI coding agent triggered each build. It's built for the agentic-workflow era, where multiple IDEs, terminals, and agents can all be driving Gradle at once.
Everything stays on your machine. No telemetry; command lines and logs are best-effort redacted before they're ever stored. Outbound network use is limited to GitHub Releases update checks at startup or from Settings, plus installer downloads that you explicitly approve.
Live monitor with concurrent Gradle activity and the selected daemon inspector.
- Every running Gradle-related JVM, classified by type with an at-a-glance icon:
- 🐘 Gradle daemon · 🐘+🔧 Gradle wrapper · the Kotlin mark for the Kotlin daemon · 🧪 test worker · ☕ other Gradle-related JVM
- Per-process RSS, CPU, and live-ticking uptime
- Headline stats: active processes, total RSS, highest-memory PID, active projects
- Highlight badges: high/critical memory,
MULTI-BUILD(a project with concurrent build invocations),AUTOMATED(CI/script/agent flags) - Per-daemon detail with
-Xmx, GC, working dir, full (redacted) command line, and a live tail of the daemon log - One-click switch to headless mode from the toolbar when you want collection to continue without the desktop window
Visual timeline of resident memory and configured heap for live Gradle processes.
- Full-width RSS & Heap chart over a rolling window
- Solid series for RSS, dashed for configured heap (
-Xmx) when recoverable - Totals plus a legend for every process — click to show/hide series or focus selected heap
Build history with outcomes, source and agent tags, resource peaks, and a captured log excerpt.
- Every reconstructed build, with start time, project, duration, peak RSS, status (✓ success / ✗ failed / ⚠ interrupted / ◐ completed), source (terminal / IDE), and agent
- Filter by project and time range
- Per-build detail with resource peaks and a captured log excerpt
- Configurable history retention (default 15 days, range 1–90). Lowering it purges out-of-range entries immediately.
Daemonitor can keep collecting in the background without the desktop window. Use the toolbar action
to switch from desktop to headless mode, or start it directly with --headless. Packaged headless
mode uses the same local database and settings as the desktop app, shows a system tray/menu-bar icon
when the OS supports it, and offers Open Daemonitor and Quit Daemonitor actions from that
menu.
Daemonitor can also run as a local, read-only MCP server so agent tools can inspect retained build history and currently visible Gradle-related processes. The MCP mode uses stdio, reads the same local SQLite database as the desktop app, and exposes these tools:
daemonitor_search_history: search retained builds by id, command, project, status, source, or agent.daemonitor_builds_for_process: find retained builds and process samples for a daemon PID or process text.daemonitor_current_processes: return the Gradle-related processes visible right now.
Daemonitor fingerprints the coding agent behind a build from the environment-variable names the daemon recorded (names only — never values, staying within the redaction posture). It recognizes Claude Code, Cursor, Codex, Gemini CLI, and Aider, and flags unrecognized agents explicitly.
It also subtracts its own ambient environment before attributing: if Daemonitor itself runs inside, say, a Claude Code shell, every build would otherwise inherit those variables. Only signals that distinguish a build from Daemonitor's own session are attributed, so you don't get "everything is Claude."
- JDK 17+ to run Gradle from source. The build uses a Java 21 toolchain, which Gradle auto-provisions when a local Java 21 installation is unavailable.
- macOS, Linux, or Windows
- Permission to read your own process list and Gradle daemon logs
Daemonitor reads Gradle daemon logs under ~/.gradle/daemon/<version>/ and enumerates processes
owned by the current user.
Daemonitor is distributed as a native desktop app per operating system:
| OS | Package |
|---|---|
| macOS | .dmg |
| Windows | .msi |
| Linux | .deb |
The installed app does not require a project-local Gradle setup. It only reads local process metadata and Gradle daemon logs for the current user.
Linux distribution starts with the GitHub Releases .deb. The follow-up update strategy is a signed
apt repository with advisory in-app prompts only; see
Linux Update Distribution.
Daemonitor checks GitHub Releases once at startup and marks the Settings tab as Settings (1) when
a newer version is available. The Settings tab can also check manually. When a newer release is
available, Daemonitor downloads the matching installer for the current operating system only after
you approve it, verifies the SHA-256 checksum from release metadata, and opens the local installer.
The app does not silently install updates.
Source builds require JDK 17+ to launch Gradle; the pinned Java 21 toolchain is provisioned automatically when it is not installed locally.
./gradlew runTo collect and persist data without starting Compose or requiring a display server:
./gradlew runHeadlessPackaged launchers also accept --headless. Headless and desktop modes use the same local database
and retention setting. On desktop operating systems, the tray/menu-bar icon can reopen Daemonitor or
quit the collector. Stop source-run headless mode with Ctrl+C or the service manager's normal
termination signal.
Daemonitor exposes read-only MCP from the desktop app:
- Open Daemonitor.
- Go to Settings.
- Enable MCP.
- Copy the local URL and token shown in Settings into your MCP client.
Example HTTP MCP client config:
{
"mcpServers": {
"daemonitor": {
"url": "http://127.0.0.1:17333/mcp",
"headers": {
"Authorization": "Bearer <token from Daemonitor Settings>"
}
}
}
}The in-app MCP server binds only to 127.0.0.1 and requires the token shown in Settings. Keep
Daemonitor open while your MCP client is connected. It is read-only: it can search Daemonitor's
retained SQL history and poll current Gradle-related processes, but it does not start, stop, or
modify builds.
Clients that only support stdio can still start Daemonitor through the native packaged launcher with
the --mcp argument. Do not point a stdio MCP client at ./gradlew run; Gradle writes its own
progress output to stdout, which can corrupt stdio MCP messages. For local development, build a
distributable first and use the launcher inside build/compose/binaries/main/app/.
Example stdio MCP client config:
{
"mcpServers": {
"daemonitor": {
"command": "/Applications/Daemonitor.app/Contents/MacOS/Daemonitor",
"args": ["--mcp"]
}
}
}Replace command with the installed launcher path for your operating system. The stdio server exits
when the client disconnects.
The Compose Gradle plugin packages a platform-native installer via jpackage (must be built on the
target OS):
./gradlew packageDmg # macOS (.dmg)
./gradlew packageMsi # Windows (.msi)
./gradlew packageDeb # Linux (.deb)Tag-triggered GitHub releases also publish latest.json, update.json, and checksums.txt next
to the native installers. The updater-facing metadata contract is documented in
docs/update-metadata.md.
./gradlew testThe suite includes unit tests for the collection/classification/aggregation logic and Compose UI tests that mount the real screens and assert on rendered nodes. CI runs the full suite on Linux, Windows, and macOS (Linux uses a virtual display for the UI tests).
The checked-in screenshots are rendered from synthetic, privacy-safe sample state using the real Compose screens at the application's native 1180×760 window size. After a visible UI change, run:
./gradlew captureReadmeScreenshots testReview the files in docs/images/ before committing. Keep sample paths and logs synthetic; never
capture a locally running instance with personal paths, environment values, or command-line secrets.
Daemonitor combines two signals:
- Process polling (via OSHI) every 2 s — RSS, CPU, uptime, and JVM flags for the current user's Gradle-related JVMs.
- Daemon-log parsing — build existence, start/end, outcome, working directory, and the environment-variable names used for source/agent attribution.
A build is reconstructed by correlating a daemon's busy→idle bracket (which must contain a real build start) with the resource samples taken inside that window. Confirmed builds and samples are persisted to a local SQLite database (owner-only file permissions; excluded from Time Machine on macOS) and purged by the configured retention window.
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Daemonitor |
| Linux | $XDG_DATA_HOME/Daemonitor (or ~/.local/share/Daemonitor) |
| Windows | %LOCALAPPDATA%\Daemonitor |
Holds watcher.db (history) and settings.properties (retention).
Kotlin · Compose for Desktop (Material 3) · OSHI · SQLDelight + JDBC SQLite · Kotlin Coroutines.
All data is local. Command lines and daemon-log lines may contain sensitive values, so they are redacted on a best-effort basis before storage, and the database file is created with owner-only permissions. Daemonitor only makes outbound requests for GitHub Releases update checks at startup or from Settings, and for installer downloads that you explicitly approve.
Early (v1.0.6). The data model and detection heuristics are evolving; see requirements.md for the
original specification.