{"id":49522029,"url":"https://github.com/maydali28/claudewatch","last_synced_at":"2026-05-30T12:01:00.987Z","repository":{"id":354414918,"uuid":"1219094999","full_name":"maydali28/claudewatch","owner":"maydali28","description":"Your Claude Code companion that tracks cost, tokens, and sessions in real time.","archived":false,"fork":false,"pushed_at":"2026-05-29T16:29:41.000Z","size":99427,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T17:11:18.797Z","etag":null,"topics":["ai","claude-code","cost-tracking","observability","token-usage"],"latest_commit_sha":null,"homepage":"https://claudewatch.mohamedalimay.dev/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maydali28.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"maydali28"}},"created_at":"2026-04-23T14:19:39.000Z","updated_at":"2026-05-29T16:12:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/maydali28/claudewatch","commit_stats":null,"previous_names":["maydali28/claudewatch"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/maydali28/claudewatch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maydali28%2Fclaudewatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maydali28%2Fclaudewatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maydali28%2Fclaudewatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maydali28%2Fclaudewatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maydali28","download_url":"https://codeload.github.com/maydali28/claudewatch/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maydali28%2Fclaudewatch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33691312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","claude-code","cost-tracking","observability","token-usage"],"created_at":"2026-05-02T00:04:34.847Z","updated_at":"2026-05-30T12:01:00.962Z","avatar_url":"https://github.com/maydali28.png","language":"TypeScript","funding_links":["https://github.com/sponsors/maydali28"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"resources/ring/png/claudewatch-ring-256.png\" alt=\"ClaudeWatch\" width=\"96\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eClaudeWatch\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Finally know what Claude Code is actually doing — and what it's costing you.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/maydali28/claudewatch/actions/workflows/release.yml\"\u003e\n    \u003cimg src=\"https://github.com/maydali28/claudewatch/actions/workflows/release.yml/badge.svg\" alt=\"Build \u0026 Release\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/maydali28/claudewatch/releases/latest\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/maydali28/claudewatch?label=latest\" alt=\"Latest Release\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/maydali28/claudewatch/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/downloads/maydali28/claudewatch/total?label=downloads\" alt=\"Total Downloads\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-blue\" alt=\"Platforms\" /\u003e\n  \u003ca href=\"LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.producthunt.com/products/claudewatch-2\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Product%20Hunt-featured-DA552F?logo=producthunt\u0026logoColor=white\" alt=\"Product Hunt\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\nYou 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, no cloud sync, and no data leaving your machine.\n\n## Screenshots\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"screenshots/menu-bar.png\" alt=\"Menu Bar Popover\" width=\"320\" /\u003e\n  \u003cbr /\u003e\u003cem\u003eMenu bar popover — live stats at a glance\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"screenshots/session.png\" alt=\"Session Explorer\" width=\"700\" /\u003e\n  \u003cbr /\u003e\u003cem\u003eSession Explorer — full transcript with search and detail panel\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"screenshots/analytics.png\" alt=\"Analytics Dashboard\" width=\"700\" /\u003e\n  \u003cbr /\u003e\u003cem\u003eAnalytics Dashboard — six tabs covering cost, cache, models, latency, and effort\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"screenshots/skills.png\" alt=\"Skills Browser\" width=\"700\" /\u003e\n  \u003cbr /\u003e\u003cem\u003eSkills — inline validation and markdown preview\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"screenshots/pricing.png\" alt=\"Pricing Engine\" width=\"700\" /\u003e\n  \u003cbr /\u003e\u003cem\u003ePricing Engine — Anthropic API and Vertex AI cost tables\u003c/em\u003e\n\u003c/p\u003e\n\n## Table of Contents\n\n- [How It Works](#how-it-works)\n- [Installation](#installation)\n- [Requirements](#requirements)\n- [Troubleshooting](#troubleshooting)\n- [Features](#features)\n  - [Menu Bar Popover](#menu-bar-popover)\n  - [Session Explorer](#session-explorer)\n  - [Analytics Dashboard](#analytics-dashboard)\n  - [Hooks](#hooks)\n  - [Commands](#commands)\n  - [Skills](#skills)\n  - [MCPs](#mcps)\n  - [Memory](#memory)\n  - [Pricing Engine](#pricing-engine)\n  - [Auto-Update](#auto-update)\n- [Getting Started (Development)](#getting-started-development)\n  - [Environment Variables](#environment-variables)\n- [Project Structure](#project-structure)\n- [Tech Stack](#tech-stack)\n- [Available Scripts](#available-scripts)\n- [IPC Architecture](#ipc-architecture)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## How It Works\n\nClaudeWatch watches `~/.claude/projects/` using [chokidar](https://github.com/paulmillr/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.\n\nOn 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.\n\nThe 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.\n\n---\n\n## Installation\n\n### macOS\n\n#### Homebrew (recommended)\n\n```bash\nbrew tap maydali28/claudewatch\nbrew install --cask claudewatch\n```\n\n#### Direct download\n\nDownload the `.dmg` from the [latest release](https://github.com/maydali28/claudewatch/releases/latest) and drag the app to `/Applications`.\n\n#### Updating\n\nClaudeWatch 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.\n\nYou can also update via Homebrew:\n\n```bash\nbrew upgrade --cask claudewatch\n```\n\n### Windows\n\n\u003e **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.\n\nDownload `ClaudeWatch-Setup.exe` from the [latest release](https://github.com/maydali28/claudewatch/releases/latest). 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.\n\n### Linux\n#### Debian/Ubuntu (one-liner, recommended)\n\n```bash\ncurl -fsSL https://maydali28.github.io/claudewatch/install.sh | sudo bash\n```\n\nThe 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:\n\n```bash\ncurl -fsSL https://maydali28.github.io/claudewatch/install.sh | sudo bash -s -- --uninstall\n```\n\nPrefer to audit before running? Download first:\n\n```bash\ncurl -fsSL https://maydali28.github.io/claudewatch/install.sh -o install.sh\nless install.sh    # review\nsudo bash install.sh\n```\n\n#### Debian/Ubuntu (manual APT setup)\n\n```bash\nsudo install -d -m 0755 /etc/apt/keyrings\ncurl -fsSL https://maydali28.github.io/claudewatch/pubkey.gpg \\\n  | sudo gpg --dearmor -o /etc/apt/keyrings/claudewatch.gpg\necho \"deb [signed-by=/etc/apt/keyrings/claudewatch.gpg] https://maydali28.github.io/claudewatch stable main\" \\\n  | sudo tee /etc/apt/sources.list.d/claudewatch.list\nsudo apt update\nsudo apt install claudewatch\n```\n\nFuture updates apply with `sudo apt upgrade`.\n\n#### Direct download\n\nDownload the `.deb` (Debian/Ubuntu) or `.rpm` (Fedora/RHEL) from the [latest release](https://github.com/maydali28/claudewatch/releases/latest).\n\n---\n\n## Requirements\n\n- **Claude Code** installed and used at least once (creates `~/.claude/projects/`)\n- **macOS** Sonoma 14+ / **Windows** 10+ / **Linux** (glibc 2.28+)\n- Node.js 20+ and pnpm 10+ (development only)\n\n---\n\n## Features\n\n### Menu Bar Popover\n\nClaudeWatch 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:\n\n- **Today's cost, tokens, sessions, and projects** — four numbers that update the moment a session file changes\n- **Live active session card** — when Claude Code is working right now, you see the project, model, and live token count with a pulsing green indicator\n- **Recent sessions** — the last few sessions across all projects with relative timestamps and cost, clickable to jump directly to the full transcript\n- **Quick actions** — open the dashboard, check for updates, or quit\n\n### Session Explorer\n\nEvery conversation Claude Code has ever had, fully accessible and searchable.\n\n- **Real-time updates** — sessions appear the moment Claude Code writes a new file; no refresh needed\n- **Full transcript view** — browse the complete conversation including user messages, assistant responses, thinking blocks, tool calls, file reads, and bash output\n- **In-session search** — press `Cmd+F` to find anything inside the open session; collapsed blocks auto-expand on match\n- **Global search** — full-text search across every session, every project\n- **Session detail panel** — tokens, cost, compaction count, subagent usage, thinking effort distribution, and error flags all in one place\n- **Custom tags** — label sessions by feature, client, or sprint; tags persist and are filterable\n- **Export** — save any session as **Markdown** or **JSON** with full metadata\n\n### Analytics Dashboard\n\nSix 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, 90d, All, or custom) and project filter so comparisons are always consistent.\n\n**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.\n\n**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.\n\n**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.\n\n**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.\n\n**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.\n\n**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.\n\n### Hooks\n\nAll 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.\n\n### Commands\n\nEvery 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.\n\n### Skills\n\nAll 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.\n\n### MCPs\n\nEvery Model Context Protocol server configured across global, project, and local settings, with live connection status (connected / failed / unknown). Each entry shows:\n\n- Transport type (stdio / sse / http) and config level (global / project / local)\n- Full command, arguments, and masked environment variables\n- Active capabilities: Tools, Prompts, Resources — with strikethrough for inactive ones\n- Last seen timestamp\n\n### Memory\n\nAll 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.\n\n### Pricing Engine\n\nCost is estimated from the raw token counters stored in each JSONL session file. Three pricing tables are built in:\n\n- **Anthropic API (direct)** — standard published rates including cache creation charges\n- **Vertex AI (Global)** — same input/output rates, cache creation is free\n- **Vertex AI (Regional)** — 10% surcharge over global rates on input, output, and cache read\n\nThe model ID (e.g. `claude-opus-4-6-20250313`) is mapped to a pricing family, with version-aware handling because Opus 4.5+ and Haiku 4.5+ have different rates from their predecessors. Switching pricing provider in settings recalculates all cost estimates across the app immediately.\n\nThese are estimates based on published pricing, not actual billed amounts.\n\n### Auto-Update\n\n- macOS: DMG download with signature verification, or `brew upgrade --cask claudewatch`\n- Windows: Squirrel auto-update applies silently\n- Linux: DEB / RPM manual download from releases\n\n---\n\n## Getting Started (Development)\n\n### 1. Clone and install\n\n```bash\ngit clone https://github.com/maydali28/claudewatch.git\ncd claudewatch\npnpm install\n```\n\n### 2. Configure environment variables\n\n```bash\ncp .env.example .env.local\n```\n\nOpen `.env.local` and fill in your values. The file is gitignored — never commit it.\n\n#### Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `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)**. |\n| `MAIN_VITE_RELEASE_SERVER_URL` | No | Base URL for the auto-updater release feed (Hazel or generic provider). Leave empty to disable update checks. |\n| `MAIN_VITE_GITHUB_RELEASES_URL` | No | GitHub releases base URL for fetching and verifying release manifests. |\n| `MAIN_VITE_BREW_CASK_NAME` | No | Homebrew cask name used in `brew upgrade --cask \u003cname\u003e` on macOS. |\n| `VITE_WEBSITE_URL` | No | Project website URL shown in About panels. |\n| `VITE_REPO_URL` | No | GitHub repository URL shown in About panels. |\n| `ANALYZE` | No | Set to `true` to open a bundle size visualiser (`bundle/stats.html`) after `pnpm build`. Defaults to `false`. |\n\n`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.\n\nVariables 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`](.env.example).\n\nThe following secrets must be set in your GitHub repository (**Settings → Secrets and variables → Actions**) and are never stored in `.env` files.\n\n**Build-time configuration** (read by `pnpm make` on every platform):\n\n| Secret | Purpose |\n|--------|---------|\n| `MAIN_VITE_SENTRY_DSN` | Sentry DSN for crash reports |\n| `MAIN_VITE_RELEASE_SERVER_URL` | Auto-updater release feed URL |\n| `MAIN_VITE_GITHUB_RELEASES_URL` | GitHub releases base URL for manifest verification |\n| `MAIN_VITE_BREW_CASK_NAME` | Homebrew cask name shown in the in-app upgrade hint |\n| `VITE_WEBSITE_URL` | Project website URL |\n| `VITE_REPO_URL` | GitHub repository URL |\n| `HOMEBREW_TAP_TOKEN` | PAT with write access to the Homebrew tap repo |\n| `APT_GPG_PRIVATE_KEY` | GPG private key used to sign the APT repository metadata |\n\n**macOS code-signing and notarization** (consumed only on the `macos-14` runner — see [`.github/workflows/release.yml`](.github/workflows/release.yml)):\n\n| Secret | Purpose |\n|--------|---------|\n| `MACOS_CERTIFICATE` | base64-encoded `.p12` export of the Developer ID Application certificate |\n| `MACOS_CERTIFICATE_PWD` | password used when exporting the `.p12` |\n| `APPLE_API_KEY` | base64-encoded `AuthKey_XXXX.p8` from App Store Connect (used by `notarytool`) |\n| `APPLE_API_KEY_ID` | App Store Connect API Key ID (10 chars) |\n| `APPLE_API_ISSUER` | App Store Connect Issuer ID (UUID) |\n\nThe 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`](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.\n\nTo produce the base64 inputs locally:\n\n```bash\nbase64 -i DeveloperIDApplication.p12 | pbcopy   # → MACOS_CERTIFICATE\nbase64 -i AuthKey_XXXX.p8 | pbcopy              # → APPLE_API_KEY\n```\n\nCI secrets override the defaults baked into `.env` at build time.\n\n### 3. Run in development mode\n\n```bash\npnpm dev\n```\n\nThis 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.\n\n---\n\n## Troubleshooting\n\n### Linux\n\n#### `chrome-sandbox` permissions error\n\nOn Linux, running `pnpm start` (or `pnpm dev`) may fail with:\n\n```\nFATAL:setuid_sandbox_host.cc(166)] The SUID sandbox helper binary was found,\nbut is not configured correctly.\n```\n\nElectron's Chromium sandbox requires the `chrome-sandbox` binary to be owned by root with mode `4755`. After `pnpm install`, fix the permissions once:\n\n```bash\nsudo chown root:root node_modules/electron/dist/chrome-sandbox\nsudo chmod 4755 node_modules/electron/dist/chrome-sandbox\n```\n\nThen run `pnpm start` normally (without `sudo`).\n\n**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:\n\n```bash\nELECTRON_DISABLE_SANDBOX=1 pnpm start\n```\n\n---\n\n## Project Structure\n\n```\nclaudewatch/\n├── src/\n│   ├── main/                    # Main process (Node.js / Electron)\n│   │   ├── index.ts             # App entry, lifecycle, tray setup\n│   │   ├── window-manager.ts    # Dashboard + tray popover windows\n│   │   ├── tray-manager.ts      # System tray icon \u0026 context menu\n│   │   ├── services/            # Core business logic\n│   │   │   ├── session-parser.ts      # JSONL streaming parser entry\n│   │   │   ├── parsers/               # Metadata / full / subagent parsers\n│   │   │   ├── session-search.ts      # Cross-session full-text search\n│   │   │   ├── analytics-engine.ts    # Aggregation across sessions\n│   │   │   ├── pricing-engine.ts      # Token cost calculations\n│   │   │   ├── lint-service.ts        # Rule runner\n│   │   │   ├── lint-rules/            # Rule implementations (grouped by prefix)\n│   │   │   ├── file-watcher.ts        # chokidar wrapper\n│   │   │   ├── project-scanner.ts     # Initial directory scan\n│   │   │   ├── config-service.ts      # Config file readers\n│   │   │   ├── secret-scanner.ts      # Credential detection\n│   │   │   ├── metadata-cache.ts      # Session metadata cache\n│   │   │   ├── scan-cache.ts          # Project scan cache\n│   │   │   ├── update-service.ts      # GitHub release fetcher\n│   │   │   ├── export-service.ts      # Markdown / JSON export\n│   │   │   └── sentry.ts              # Sentry init, enable/disable, capture helpers\n│   │   ├── ipc/                 # IPC request handlers (domain-split)\n│   │   ├── lib/                 # logger, p-limit, safe-path, app-config\n│   │   └── store/               # Persistent preferences (electron-store)\n│   │\n│   ├── renderer/src/            # Renderer process (React)\n│   │   ├── app.tsx              # Dashboard entry\n│   │   ├── tray-app.tsx         # Tray popover entry\n│   │   ├── about-app.tsx        # About window entry\n│   │   ├── onboarding-app.tsx   # Onboarding window entry\n│   │   ├── update-app.tsx       # Update window entry\n│   │   ├── components/\n│   │   │   ├── layout/          # Dashboard shell, left rail, panels\n│   │   │   ├── sessions/        # Session list + detail views\n│   │   │   ├── analytics/       # Charts and insight tabs\n│   │   │   ├── config/          # Config file browser\n│   │   │   ├── lint/            # Health gauge + rule results\n│   │   │   ├── plans/           # Plan browser\n│   │   │   ├── timeline/        # Activity timeline\n│   │   │   ├── settings/        # Preferences panels\n│   │   │   ├── tray-popover/    # Tray window UI\n│   │   │   ├── onboarding/      # First-run flow\n│   │   │   ├── update/          # Update window UI\n│   │   │   ├── about/           # About window UI\n│   │   │   ├── shared/          # Cross-feature components\n│   │   │   └── ui/              # Radix-based primitives\n│   │   ├── hooks/               # Custom React hooks\n│   │   └── store/               # Zustand stores\n│   │\n│   ├── preload/\n│   │   └── index.ts             # Context bridge for renderer ↔ main IPC\n│   │\n│   └── shared/                  # Types and utilities shared across processes\n│       ├── types/               # TypeScript interfaces\n│       ├── ipc/                 # Channel constants + typed IPC contracts\n│       ├── constants/           # Pricing tables, model metadata, lint rule meta\n│       └── utils/               # Formatting helpers, date ranges, entropy\n│\n├── resources/                   # App icons and tray assets\n├── scripts/                     # Release, changelog, bundle-size, licenses\n├── forge.config.ts              # Electron Forge packaging config\n├── electron.vite.config.mts     # electron-vite build config\n└── .github/workflows/release.yml\n```\n\n---\n\n## Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| Desktop shell | Electron 32 |\n| Build tooling | electron-vite 2, electron-forge 7 |\n| UI | React 19, TypeScript 5.6, TailwindCSS 4 |\n| Components | Radix UI primitives |\n| Charts | Recharts 2 |\n| State | Zustand 5, TanStack React Query 5 |\n| Persistence | electron-store 8 |\n| File watching | chokidar 4 |\n| Validation | Zod 4 |\n| Testing | Vitest 2, Testing Library |\n| Package manager | pnpm 10 |\n\n---\n\n## Available Scripts\n\n```bash\npnpm dev                    # Start dev server with hot reload\npnpm build                  # Compile TypeScript + bundle\npnpm typecheck              # Type-check without emitting\npnpm test                   # Run all tests\npnpm test:watch             # Watch mode\npnpm test:ui                # Vitest UI\npnpm test:coverage          # Coverage report\npnpm lint                   # ESLint check\npnpm lint:fix               # Auto-fix lint issues\npnpm format                 # Prettier formatting\npnpm format:check           # Prettier check only\npnpm depcruise              # Dependency-cruiser check\npnpm depcruise:graph        # Export dependency graph as SVG\npnpm size-check             # Bundle size guard\npnpm package                # Build + package (out/)\npnpm make                   # Build + forge make (out/make/)\npnpm publish                # Build + publish to GitHub releases\npnpm changelog              # Generate changelog since last tag\npnpm release                # Orchestrated release flow\n```\n\n---\n\n## IPC Architecture\n\nAll communication between the renderer and main process goes through typed IPC channels defined in [src/shared/ipc/contracts.ts](src/shared/ipc/contracts.ts). Every response is wrapped in a `Result\u003cT\u003e` discriminated union so the renderer never needs to catch unhandled exceptions:\n\n```ts\ntype Result\u003cT\u003e = { ok: true; data: T } | { ok: false; error: string; code?: string }\n```\n\nHandlers 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.\n\n**Renderer → Main (invoke/handle)**\n\n| Domain | Channels |\n|--------|---------|\n| Sessions | `list-projects`, `get-summary-list`, `get-parsed`, `search`, `tag`, `export` |\n| Analytics | `get` |\n| Config | `get-full`, `get-commands`, `get-skills`, `get-project-skills`, `get-mcps`, `get-memory`, `get-project-claude-mds` |\n| Lint | `run`, `get-summary` |\n| Settings | `get`, `set` |\n| Plans | `list`, `get`, `get-projects` |\n| Updates | `check`, `download`, `install`, `brew-upgrade` |\n| Tray | `open-dashboard`, `show-about`, `show-update`, `show-onboarding` |\n| App | `quit`, `get-version` |\n\n**Main → Renderer (push events)**\n\n| Event | When it fires |\n|-------|--------------|\n| `push:session-updated` | An existing session file changed |\n| `push:session-created` | A new session file was detected |\n| `push:config-changed` | A config file was modified |\n| `push:secrets-detected` | Secrets found in a session tail scan |\n| `push:update-available` | A newer release was found |\n| `push:update-service-error` | The update service surfaced an error |\n| `push:today-stats` | Today's aggregated stats changed |\n| `push:navigate-session` | Request to navigate to a specific session |\n| `push:show-update` | Open the update window |\n| `push:show-onboarding` | Open the onboarding window |\n| `push:main-error` | Unhandled main-process error |\n\n---\n\n## Contributing\n\nContributions are welcome. Here is how to get involved:\n\n### 1. Fork and branch\n\n```bash\ngit clone https://github.com/your-fork/claudewatch.git\ncd claudewatch\ngit checkout -b feat/your-feature\n```\n\n### 2. Install dependencies\n\n```bash\npnpm install\n```\n\n### 3. Make your changes\n\n- Keep TypeScript strict — no `any` unless unavoidable\n- Services belong in `src/main/services/`, UI components in `src/renderer/src/components/`\n- Add shared types to `src/shared/types/` so both processes can import them without circular dependencies\n- New lint rules go in `src/main/services/lint-rules/` and must be registered in `src/shared/constants/lint-rules.ts`\n\n### 4. Test\n\n```bash\npnpm test\npnpm typecheck\npnpm lint\n```\n\n### 5. Open a pull request\n\n- Title prefix: `feat:`, `fix:`, `refactor:`, or `docs:`\n- Describe what changed and why, not just what the diff shows\n- Reference any related issues\n\n### Reporting issues\n\nOpen an issue at [github.com/maydali28/claudewatch/issues](https://github.com/maydali28/claudewatch/issues) with:\n- OS and version\n- ClaudeWatch version (`Help → About`)\n- Steps to reproduce\n- Relevant logs (`Help → Show Logs`)\n\n---\n\n## Privacy\n\nClaudeWatch reads files from `~/.claude` on your local machine. Here is a complete list of what leaves your machine and what stays local:\n\n| What | Where it goes | When |\n|------|--------------|------|\n| Update check | `MAIN_VITE_RELEASE_SERVER_URL` server (Hazel) | On launch and periodically — version string and platform only, no identifiers |\n| Crash reports | Sentry | Only if you opt in under **Settings → Privacy** — stack traces only, see below |\n| User feedback | Sentry | Only if you opt in and click **Send feedback** |\n| Everything else | **Nowhere** | All processing is local |\n\n- **No session content, prompts, or responses are ever sent anywhere.**\n- **No file paths, project names, or usernames leave your machine.**\n- **Secret scanning runs entirely locally** — detected secrets are stored only in your local preferences file as masked fingerprints.\n- The update check sends only your current ClaudeWatch version and platform (`darwin_arm64`, etc.).\n- **Crash reporting is opt-in and off by default.** When enabled, Sentry receives only stack traces and error messages. Home-directory paths are stripped before sending (`/Users/yourname/` → `/Users/[user]/`). No session data, API keys, or file contents are ever included.\n- There is no background analytics or telemetry of any kind.\n\n---\n\n## License\n\n[MIT](LICENSE) — Copyright © 2026 Mohamed Ali May\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaydali28%2Fclaudewatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaydali28%2Fclaudewatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaydali28%2Fclaudewatch/lists"}