neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
Track Claude Code usage, tokens, estimated cost, cache and sessions from your menu bar. macOS, Windows, Linux. Local session analysis, no account.
Developer toolsTypeScript · JavaScriptGitHub @maydali28OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Your Claude Code companion that tracks cost, tokens, and sessions in real time.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Finally know what Claude Code is actually doing — and what it's costing you.
You use Claude Code every day. But do you know which sessions blew your budget? Which model is eating most of your spend? Whether your prompt cache is actually saving money? ClaudeWatch answers all of that — from your menu bar, in real time, with no accounts and no cloud sync. Session analysis runs on your machine; the only network traffic is the update check and, if you opt in, crash reports.
All screenshots use synthetic demo projects and conversations, not personal session history.Read the full README ↗You use Claude Code every day. But do you know which sessions blew your budget? Which model is eating most of your spend? Whether your prompt cache is actually saving money? ClaudeWatch answers all of that — from your menu bar, in real time, with no accounts and no cloud sync. Session analysis runs on your machine; the only network traffic is the update check and, if you opt in, crash reports.
All screenshots use synthetic demo projects and conversations, not personal session history.
ClaudeWatch watches ~/.claude/projects/ using chokidar for file system events. When Claude Code writes to a session file (JSONL format), ClaudeWatch detects the change, streams the file line-by-line without loading it fully into memory, and updates the UI in real time. There is no polling interval — changes propagate as fast as the OS delivers the event. If you relocate Claude Code's folder with CLAUDE_CONFIG_DIR (in your shell or in the env block of ~/.claude/settings.json), ClaudeWatch reads that folder instead.
On first launch, ClaudeWatch performs a one-time scan to build the project and session index. From that point, only changed files are re-parsed. Cost calculations happen inline at parse time so the analytics view never needs a separate aggregation pass.
The app runs as a standard Electron process. On macOS it appears only in the menu bar (LSUIElement equivalent via Electron's skipTaskbar). The tray popover is a frameless window pinned to the tray icon; the full dashboard is a separate browser window opened on demand.
brew tap maydali28/claudewatch
brew install --cask claudewatch
Download the .dmg from the latest release and drag the app to /Applications.
ClaudeWatch checks for updates on launch and on a periodic interval. When a new version is available, an indicator appears in the tray popover. Clicking "Install Update" downloads the release, verifies it, replaces the binary, and relaunches. No manual steps required.
You can also update via Homebrew:
brew upgrade --cask claudewatch
Note: The Windows build is not yet code-signed with a Microsoft-trusted certificate (signing certificate acquisition is in progress). On first launch, Microsoft Defender SmartScreen will show a blue "Windows protected your PC" warning. This is expected — the installer is safe, just unsigned.
Download ClaudeWatch-Setup.exe from the latest release. When the SmartScreen warning appears, click More info, then Run anyway to proceed with the install. The installer uses Squirrel, so subsequent updates apply silently in the background and will not show the warning again.
curl -fsSL https://maydali28.github.io/claudewatch/install.sh | sudo bash
The installer adds the signed APT source, verifies the signing key against a pinned fingerprint, and installs ClaudeWatch. Re-running it upgrades to the latest version. To uninstall:
curl -fsSL https://maydali28.github.io/claudewatch/install.sh | sudo bash -s -- --uninstall
Prefer to audit before running? Download first:
curl -fsSL https://maydali28.github.io/claudewatch/install.sh -o install.sh
less install.sh # review
sudo bash install.sh
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://maydali28.github.io/claudewatch/pubkey.gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/claudewatch.gpg
echo "deb [signed-by=/etc/apt/keyrings/claudewatch.gpg] https://maydali28.github.io/claudewatch stable main" \
| sudo tee /etc/apt/sources.list.d/claudewatch.list
sudo apt update
sudo apt install claudewatch
Future updates apply with sudo apt upgrade.
Download the .deb (Debian/Ubuntu) or .rpm (Fedora/RHEL) from the latest release.
~/.claude/projects/)ClaudeWatch lives in your menu bar — always one click away, never in your way. Click the icon and you get an instant snapshot of your Claude Code activity without switching apps or opening a terminal:
Every conversation Claude Code still has on disk, fully accessible and searchable.
Cmd+F to find anything inside the open session; collapsed blocks auto-expand on matchHow far back does history go? Claude Code deletes transcripts after cleanupPeriodDays (30 by default), so "All" covers roughly the last month unless you raise that setting.
Seven purpose-built analytics tabs, each answering a different question about how you use Claude Code. Every tab shares the same date range picker (Today, 7d, 30d, All, or custom) and project filter so comparisons are always consistent.
Overview — The big picture. KPI cards for sessions, messages, tokens, cache hit rate, and cost. A daily token usage chart, project cost breakdown, and a sessions table sortable by activity, tokens, or cost.
Insights — Auto-generated callouts that surface what raw numbers miss: cache efficiency drops, cost concentration, latency anomalies, frequent context compaction, and model dominance. Includes a What-If Calculator that estimates how much you would save by switching some Opus usage to Sonnet.
Cache — Your prompt cache is supposed to save money. This tab tells you whether it actually is. A hit-ratio gauge, cost savings estimate, daily trend with cache-busting day markers, and a per-session efficiency ranking.
Models — Which model is really driving your spend? Turn distribution and cost broken down by model family, a daily cost-by-model trend, and an efficiency table ranked by cost-per-turn.
Latency — Slow turns break flow. See the p50, p95, and p99 turn durations, a duration distribution histogram, and a direct comparison of normal turns versus turns after a context compaction.
Effort — Not every session is equal. Turn effort is classified into Low, Medium, High, and Ultrathink levels. See where your ultrathink budget goes, cost by effort level, and parallel tool usage distribution.
Tools — Which tools and MCP servers your sessions lean on. Calls, error rate and cost share per tool and per MCP server, configured servers nobody called, and sub-agent runs and cost by agent type.
Configuration scopes. Hooks and Commands below are both read from user (~/.claude) and project (<repo>/.claude) scopes, including settings.local.json. Plugin and managed scopes are on the roadmap.
All your Claude Code hook events in one place — no more digging through config files. Every registered hook is grouped by event type (PreToolUse, PostToolUse, PermissionDenied, SessionStart, Stop, UserPromptSubmit, Notification) and displayed with its matcher pattern, the command it runs, and its timeout setting.
Every custom slash command you have defined, rendered as markdown exactly as Claude Code sees it. Browse, search, and review your command library without leaving the app.
All installed skills — global and per-project — with their full definitions and metadata. ClaudeWatch validates each skill inline and surfaces issues directly next to the skill name: missing descriptions, naming convention violations, reserved words, and body length limits. A Preview / Raw toggle lets you read the skill as rendered markdown or inspect the raw source.
Every Model Context Protocol server configured across global, project, and local settings, with live connection status (connected / failed / unknown). Each entry shows:
All CLAUDE.md and memory files that Claude Code uses for persistent context — global, per-project, and auto-memory — browseable in one panel. Each file is rendered as markdown with a raw-text toggle, and shows size and line count so you know exactly how much context you are injecting into every session.
Cost is estimated from the raw token counters stored in each JSONL session file, at Anthropic API list rates (input, output, cache read, and 5-minute / 1-hour cache writes). Per-model overrides are available in Settings → Pricing.
The model ID is mapped to a pricing family with version-aware handling; unrecognised models are reported as unpriced rather than guessed.
These are estimates, not bills. They are estimated from recorded tokens using the configured API rates. They are not your bill or your remaining plan allowance: subscription inclusions, usage credits, discounts and charges the app doesn't price can make what you actually pay differ. Fast mode, regional inference, non-standard service tiers and web search / fetch requests are not priced; the app says how many responses used them.
brew upgrade --cask claudewatch
sudo chown -R "$(id -un)" /Applications/ClaudeWatch.app usually avoids it; otherwise an administrator password is needed.sudo apt upgrade via the signed APT repository, or manual .deb / .rpm downloadgit clone https://github.com/maydali28/claudewatch.git
cd claudewatch
pnpm install
cp .env.example .env.local
Open .env.local and fill in your values. The file is gitignored — never commit it.
| Variable | Required | Description |
|---|---|---|
MAIN_VITE_SENTRY_DSN | No | Sentry DSN for crash reports and user feedback. Leave empty to disable Sentry. Get it from your Sentry project under Settings → Client Keys (DSN). |
MAIN_VITE_RELEASE_SERVER_URL | No | Base URL for the Hazel release feed used for Linux update checks. Leave empty to disable Linux update checks; macOS and Windows check via MAIN_VITE_GITHUB_RELEASES_URL instead. |
MAIN_VITE_GITHUB_RELEASES_URL | No | GitHub releases base URL for fetching and verifying release manifests. |
MAIN_VITE_BREW_CASK_NAME | No | Homebrew cask name used in brew upgrade --cask <name> on macOS. |
VITE_WEBSITE_URL | No | Project website URL shown in About panels. |
VITE_REPO_URL | No | GitHub repository URL shown in About panels. |
ANALYZE | No | Set to true to open a bundle size visualiser (bundle/stats.html) after pnpm build. Defaults to false. |
MAIN_VITE_* variables are loaded by electron-vite and injected into the main process bundle. VITE_* variables are injected into the renderer bundle. Both are read from .env and .env.local automatically — no manual wiring needed.
Variables are baked into the app bundle at build time by electron-vite's define — there is no process.env access in the shipped binary. The authoritative reference is .env.example.
The following secrets must be set in your GitHub repository (Settings → Secrets and variables → Actions) and are never stored in .env files.
Build-time configuration (read by pnpm make on every platform):
| Secret | Purpose |
|---|---|
MAIN_VITE_SENTRY_DSN | Sentry DSN for crash reports |
MAIN_VITE_RELEASE_SERVER_URL | Auto-updater release feed URL |
MAIN_VITE_GITHUB_RELEASES_URL | GitHub releases base URL for manifest verification |
MAIN_VITE_BREW_CASK_NAME | Homebrew cask name shown in the in-app upgrade hint |
VITE_WEBSITE_URL | Project website URL |
VITE_REPO_URL | GitHub repository URL |
HOMEBREW_TAP_TOKEN | PAT with write access to the Homebrew tap repo |
APT_GPG_PRIVATE_KEY | GPG private key used to sign the APT repository metadata |
macOS code-signing and notarization (consumed only on the macos-14 runner — see .github/workflows/release.yml):
| Secret | Purpose |
|---|---|
MACOS_CERTIFICATE | base64-encoded .p12 export of the Developer ID Application certificate |
MACOS_CERTIFICATE_PWD | password used when exporting the .p12 |
APPLE_API_KEY | base64-encoded AuthKey_XXXX.p8 from App Store Connect (used by notarytool) |
APPLE_API_KEY_ID | App Store Connect API Key ID (10 chars) |
APPLE_API_ISSUER | App Store Connect Issuer ID (UUID) |
The keychain password is generated per-run inside the workflow and is not a stored secret. The signing identity (Developer ID Application: ... (TEAMID)) is read from the imported certificate at build time and exported as APPLE_SIGNING_IDENTITY, which forge.config.ts uses to pin the exact identity. If APPLE_SIGNING_IDENTITY is unset, the macOS build is produced unsigned — this is the correct behavior for local builds and is what gates the entire signing path.
To produce the base64 inputs locally:
base64 -i DeveloperIDApplication.p12 | pbcopy # → MACOS_CERTIFICATE
base64 -i AuthKey_XXXX.p8 | pbcopy # → APPLE_API_KEY
CI secrets override the defaults baked into .env at build time.
pnpm dev
This starts the electron-vite dev server with hot reload for both the main process and renderer. The tray icon will appear in your system tray.
chrome-sandbox permissions errorOn Linux, running pnpm start (or pnpm dev) may fail with:
FATAL:setuid_sandbox_host.cc(166)] The SUID sandbox helper binary was found,
but is not configured correctly.
Electron's Chromium sandbox requires the chrome-sandbox binary to be owned by root with mode 4755. After pnpm install, fix the permissions once:
sudo chown root:root node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 node_modules/electron/dist/chrome-sandbox
Then run pnpm start normally (without sudo).
Do not run pnpm start with sudo — Electron refuses to launch as root, and passing --no-sandbox to pnpm start fails because electron-vite rejects unknown CLI options. If you must disable the sandbox (e.g. inside a container or VM where setuid is unavailable), use the env var instead:
ELECTRON_DISABLE_SANDBOX=1 pnpm start
claudewatch/
├── src/
│ ├── main/ # Main process (Node.js / Electron)
│ │ ├── index.ts # App entry, lifecycle, tray setup
│ │ ├── window-manager.ts # Dashboard + tray popover windows
│ │ ├── tray-manager.ts # System tray icon & context menu
│ │ ├── services/ # Core business logic
│ │ │ ├── session-parser.ts # JSONL streaming parser entry
│ │ │ ├── parsers/ # Metadata / full / subagent parsers
│ │ │ ├── session-search.ts # Cross-session full-text search
│ │ │ ├── analytics-engine.ts # Aggregation across sessions
│ │ │ ├── pricing-engine.ts # Token cost calculations
│ │ │ ├── lint-service.ts # Rule runner
│ │ │ ├── lint-rules/ # Rule implementations (grouped by prefix)
│ │ │ ├── file-watcher.ts # chokidar wrapper
│ │ │ ├── project-scanner.ts # Initial directory scan
│ │ │ ├── config-service.ts # Config file readers
│ │ │ ├── plans-service.ts # Plan file discovery and parsing
│ │ │ ├── secret-scanner.ts # Credential detection
│ │ │ ├── metadata-cache.ts # Session metadata cache
│ │ │ ├── scan-cache.ts # Project scan cache
│ │ │ ├── update-service.ts # GitHub release fetcher
│ │ │ ├── export-service.ts # Markdown / JSON / CSV export
│ │ │ ├── sentry-scrub.ts # Strips PII from Sentry events before send
│ │ │ └── sentry.ts # Sentry init, enable/disable, capture helpers
│ │ ├── ipc/ # IPC request handlers (domain-split)
│ │ ├── lib/ # logger, p-limit, safe-path, app-config
│ │ └── store/ # Persistent preferences (electron-store)
│ │
│ ├── renderer/src/ # Renderer process (React)
│ │ ├── app.tsx # Dashboard entry
│ │ ├── tray-app.tsx # Tray popover entry
│ │ ├── about-app.tsx # About window entry
│ │ ├── onboarding-app.tsx # Onboarding window entry
│ │ ├── update-app.tsx # Update window entry
│ │ ├── components/
│ │ │ ├── layout/ # Dashboard shell, left rail, panels
│ │ │ ├── sessions/ # Session list + detail views
│ │ │ ├── analytics/ # Charts and insight tabs
│ │ │ ├── config/ # Config file browser
│ │ │ ├── lint/ # Health gauge + rule results
│ │ │ ├── plans/ # Plan browser
│ │ │ ├── settings/ # Preferences panels
│ │ │ ├── tray-popover/ # Tray window UI
│ │ │ ├── onboarding/ # First-run flow
│ │ │ ├── update/ # Update window UI
│ │ │ ├── about/ # About window UI
│ │ │ ├── shared/ # Cross-feature components
│ │ │ └── ui/ # Radix-based primitives
│ │ ├── hooks/ # Custom React hooks
│ │ └── store/ # Zustand stores
│ │
│ ├── preload/
│ │ └── index.ts # Context bridge for renderer ↔ main IPC
│ │
│ └── shared/ # Types and utilities shared across processes
│ ├── types/ # TypeScript interfaces
│ ├── ipc/ # Channel constants + typed IPC contracts
│ ├── constants/ # Pricing tables, model metadata, lint rule meta
│ └── utils/ # Formatting helpers, date ranges, entropy
│
├── resources/ # App icons and tray assets
├── scripts/ # Release, changelog, bundle-size, licenses
├── forge.config.ts # Electron Forge packaging config
├── electron.vite.config.mts # electron-vite build config
└── .github/workflows/release.yml
| Layer | Technology |
|---|---|
| Desktop shell | Electron 43 |
| Build tooling | electron-vite 5, electron-forge 7 |
| UI | React 19, TypeScript 6, TailwindCSS 4 |
| Components | Radix UI primitives |
| Charts | Recharts 3 |
| State | Zustand 5, TanStack React Query 5 |
| Persistence | electron-store 11 |
| File watching | chokidar 5 |
| Validation | Zod 4 |
| Testing | Vitest 4, Testing Library |
| Package manager | pnpm 10 |
pnpm dev # Start dev server with hot reload
pnpm build # Compile TypeScript + bundle
pnpm typecheck # Type-check without emitting
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:ui # Vitest UI
pnpm test:coverage # Coverage report
pnpm lint # ESLint check
pnpm lint:fix # Auto-fix lint issues
pnpm format # Prettier formatting
pnpm format:check # Prettier check only
pnpm depcruise # Dependency-cruiser check
pnpm depcruise:graph # Export dependency graph as SVG
pnpm size-check # Bundle size guard
pnpm verify:accounting # Real-history accounting reconciliation (opt-in, reads ~/.claude)
pnpm smoke:preferences # Preferences smoke test
pnpm package # Build + package (out/)
pnpm make # Build + forge make (out/make/)
pnpm publish # Build + publish to GitHub releases
pnpm changelog # Generate changelog since last tag
All communication between the renderer and main process goes through typed IPC channels defined in src/shared/ipc/contracts.ts. Every response is wrapped in a Result<T> discriminated union so the renderer never needs to catch unhandled exceptions:
type Result<T> = { ok: true; data: T } | { ok: false; error: string; code?: string }
Handlers live in src/main/ipc/ and are registered at startup. The preload script exposes a typed window.claudewatch surface via Electron's context bridge, keeping the renderer isolated from Node.js APIs.
Renderer → Main (invoke/handle)
| Domain | Channels |
|---|---|
| Sessions | list-projects, get-summary-list, get-parsed, search, tag, export |
| Analytics | get |
| Config | get-full, get-commands, get-skills, get-project-skills, get-mcps, get-memory, get-project-claude-mds |
| Lint | run, get-summary |
| Settings | get, set |
| Plans | list, get, get-projects |
| Updates | check, download, install, resize-window |
| Tray | get-snapshot, open-dashboard, show-about, show-update, show-onboarding |
| App | quit, relaunch, get-version, get-paths |
Main → Renderer (push events)
| Event | When it fires |
|---|---|
push:session-updated | An existing session file changed |
push:session-created | A new session file was detected |
push:session-deleted | A session transcript was deleted from disk |
push:config-changed | A config file was modified |
push:update-available | A newer release was found |
push:update-service-error | The update service surfaced an error |
push:today-stats | Today's aggregated stats changed |
push:navigate-session | Request to navigate to a specific session |
push:show-update | Open the update window |
push:show-onboarding | Open the onboarding window |
push:preferences-changed | Preferences were saved, for every renderer surface to apply |
push:main-error | Unhandled main-process error |
Contributions are welcome. Here is how to get involved:
git clone https://github.com/your-fork/claudewatch.git
cd claudewatch
git checkout -b feat/your-feature
pnpm install
any unless unavoidablesrc/main/services/, UI components in src/renderer/src/components/src/shared/types/ so both processes can import them without circular dependenciessrc/main/services/lint-rules/ and must be registered in src/shared/constants/lint-rules.tspnpm test
pnpm typecheck
pnpm lint
feat:, fix:, refactor:, or docs:Open an issue at github.com/maydali28/claudewatch/issues with:
Help → About)Help → Show Logs)ClaudeWatch reads files from ~/.claude on your local machine. Here is a complete list of what leaves your machine and what stays local:
| What | Where it goes | When |
|---|---|---|
| Update check | GitHub releases feed via electron-updater (macOS, Windows), or the MAIN_VITE_RELEASE_SERVER_URL / Hazel server (Linux) | On launch and periodically — version string and platform only, no identifiers |
| Crash reports | Sentry | Only if you opt in under Settings → Privacy — error reports when an error occurs, see below |
| User feedback | Sentry | Only if you opt in and click Send feedback |
| Everything else | Nowhere | All processing is local |
[user] in these paths on macOS, Windows and Linux — including the username segment inside Claude Code's encoded project folder names (e.g. -Users-[user]-Workspace-myproject) — and your local account name is redacted. Project names and the rest of the path are not removed and are sent as-is.darwin_arm64, etc.).MIT — Copyright © 2026 Mohamed Ali May