Skip to content

Repository files navigation

CodePulse icon CodePulse

macOS validation macOS 13+ Sparkle 2.9.2

CodePulse is a native macOS menu-bar timer, coding journal, and local insights tool for developers. It is lightweight and local-first: there are no accounts, cloud sync, telemetry, product analytics, or application-usage history. Optional application automation observes only the current frontmost bundle identifier while an explicit rule is enabled; it does not inspect windows or retain app history. CodePulse contacts GitHub only to check for and download authenticated app updates or to optionally enrich a local session with read-only repository, pull request, and developer-tool metadata.

The current release candidate is CodePulse 1.5.1 (build 1501). It includes Multi-Project Workspaces, concurrent active Sessions with stable UUIDs, and thread-native Codex/OpenCode ownership across the same Project or different Workspaces. Workspace Intelligence adds deterministic cross-project activity patterns, Resume Context, and local continuation suggestions. Projects remain the ownership and identity boundary; Workspaces are an organizational aggregate scope. These capabilities, like the existing Actionable Insights experience, remain native macOS, local-first, privacy-conscious, and free of telemetry or cloud analytics; all intelligence is deterministic and local.

v1.5 — Concurrent Sessions & Thread-Native Tracking

The implemented design is documented in the frozen normative v1.5 Concurrent Sessions & Thread-Native Tracking specification. It provides first-class concurrent CodePulse Sessions, thread-native Codex/OpenCode ownership by (tool, externalSessionID), same-Project and cross-Workspace tracking, independent manual/automated lifecycle and Git capture, a multi-session menu-bar hub, overlap-safe Insights, schema/backup migration, and local metadata-only privacy. The codepulsectl lifecycle is Session-ID targeted pause/resume/finish and all-active status; save, discard, and outcome editing remain in-app lifecycle operations rather than new CLI verbs. v1.5 also freezes application-trigger automation at one application-owned Session while allowing it to coexist with manual and Developer-Tool Sessions. Active Time is overlap-safe wall-clock coverage, while Session Activity is the sum of each Session's activity; Focus calculations use the same overlap-safe foundation.

CodePulse menu-bar timer with a running coding session

Screenshots

History

CodePulse History showing privacy-safe sample coding sessions

Insights

CodePulse Insights showing local summary metrics, Goal vs Actual, Project Outcomes, Focus Patterns, activity, work types, and project totals

Settings

CodePulse Settings showing the General, Projects, Automation, and Data categories

What it does

  • Starts, pauses, resumes, and finishes focused work sessions from the menu bar.
  • Records optional projects, work types, goals, and outcomes in a searchable coding journal.
  • Captures best-effort local Git context without changing the repository.
  • GitHub context — associates local sessions with their GitHub repository and optionally their current pull request when the repository has a GitHub remote.
  • Records Codex and/or OpenCode participation across concurrent Sessions using only local lifecycle metadata. A Developer-Tool Thread identifier is routing metadata and is not the same thing as Project identity.
  • Optionally starts, pauses, resumes, and saves a session from configured Codex or OpenCode lifecycle signals. Session Automation is disabled by default and never takes control of a manually started session.
  • Saves reusable Session Presets for one-action manual Quick Start or eligible automation rules.
  • Optionally starts and maintains a session while a configured application is frontmost, matching by bundle identifier rather than display name.
  • Provides the local codepulsectl command for scriptable status, preset/manual start, pause, resume, and finish control while CodePulse is running.
  • Provides richer local Insights for active time, sessions, projects, work types, developer-tool participation, Git activity, and GitHub context with native Swift Charts. Focus Patterns report deterministic focus blocks, sustained-focus time and share, rapid identified project switches, and local time-of-day patterns from existing session timing and pause data; they do not measure human productivity, cognition, or efficiency.
  • Project Outcomes adds deterministic per-project summaries for completed sessions, including Goal-vs-Actual states, recent recorded Goal/Actual pairs, and goals needing a recorded outcome. It uses no AI and never decides whether work succeeded, failed, finished, or was abandoned.
  • Exports the currently filtered History as standard UTF-8 CSV.
  • Exports the currently selected Insights timeframe and project as a deterministic local Markdown report.
  • Optionally delivers opt-in daily and weekly local notification digests for the previous completed day or week, computed entirely on this Mac.
  • Archives projects that are no longer active without deleting their saved sessions, Insights, exports, presets, or automation rules.
  • Organizes projects into persisted Multi-Project Workspaces with workspace switching, scoped History and Insights, a Workspace Dashboard, and deterministic Workspace Intelligence for cross-project patterns, Resume Context, and local continuation suggestions.
  • Exports and restores a versioned JSON backup of local CodePulse state.

Download and install

CodePulse requires macOS 13 or later and is distributed as a Universal 2 app for Apple silicon and Intel Macs.

Download the latest DMG from GitHub Releases, open it, and drag CodePulse to Applications. The downloaded build is intentionally not Developer ID signed or notarized; it is ad-hoc signed locally for macOS runtime compatibility. Ad-hoc signing does not establish publisher identity or notarization trust, so macOS may still require an explicit first-launch approval. Follow the safe first-launch instructions in docs/releasing.md; do not disable Gatekeeper globally.

Authenticated in-app updates are provided by Sparkle. After the initial installation, use Settings → General → Check for Updates… or allow the automatic update check.

Quick start

  1. Click the CodePulse item in the menu bar.
  2. Optionally choose a project and work type, then describe the session goal.
  3. Start the session and pause or resume it as needed.
  4. Finish the session, record an optional outcome, and save it to History.
  5. Open History to search, filter, or edit saved sessions, or open Insights to review local activity and context-derived summaries.
  6. Open Insights to review Goal vs Actual and Project Outcomes. Project Outcomes shows the goals and outcomes you recorded for completed sessions, with missing outcomes called Needs Follow-Up. These states describe recorded text; they do not classify success, failure, completion, or abandonment.
  7. Review Focus Patterns such as longest and sustained focus blocks, project switches, and local time-of-day distribution. These are observable timing summaries, not a productivity score.
  8. If desired, create a Settings → Projects → Session Presets entry for a reusable Quick Start, then open Settings → Automation → Developer Integrations to enable Codex or OpenCode context enrichment. Integrations are optional and separate from Settings → Automation → Session Automation, which is also optional and disabled by default.
  9. For a shell, Shortcuts Run Shell Script, Raycast, Alfred, Stream Deck, or IDE task, use the bundled codepulsectl command described below.

Projects are optional. Adding a project grants CodePulse access only to the folder you select, allowing it to read local Git metadata for that project.

Getting started

On a fresh installation, CodePulse shows a short native introduction covering local storage, optional Projects, and the first-session workflow. Accounts, developer integrations, and Session Automation are optional. You can revisit the introduction later from Settings → General → Show Introduction….

Backup and restore

Use Settings → Data → Backup & Restore and choose Export Backup… to save a portable, pretty-printed JSON backup of local CodePulse projects, settings, presets, automation rules, saved sessions, captured Git/GitHub context, developer-tool session context, and any active-session timeline. The current format is codepulse-backup version 3 with schema 3 and an explicit activeSessions collection, including when it is empty. CodePulse imports backup versions 1, 2, and 3 and migrates them in memory while preserving active Session UUIDs and timelines. Multiple active Session timelines may be included. Machine-local replay ledgers, retired-Thread tombstones, reservations, control processing, and transient capture state are not exported.

Use Settings → Data → Backup & Restore and choose Restore Backup… to inspect the selected backup before confirming. Restore replaces the current local CodePulse data; it does not merge sessions or projects. CodePulse first creates and verifies a private automatic recovery backup at ~/Library/Application Support/CodePulse/Backups/Pre-Restore Backup ...json. The newest five automatic pre-restore recovery backups are retained. A failed restore leaves the current data in place or reports whether automatic rollback succeeded.

Lifecycle changes are durably committed before CodePulse publishes start, pause, resume, finish, save, or discard in memory. A failed lifecycle commit leaves the prior session state available for retry. Finishing sessions and pending automatic saves remain recoverable across relaunches, and repeated save/replay attempts cannot create a second completed record for the same session.

If an existing state.json cannot be read, CodePulse does not treat the installation as fresh and does not overwrite the file. It opens a small read-only recovery window with Restore Backup…, Show Data Folder, and Quit CodePulse. When the saved schema is newer than this installation supports—for example, after opening current data with an older CodePulse—the window identifies the version mismatch and recommends updating or reinstalling the newer app. Restore remains available as an explicit alternative, but is not presented as the default remedy for newer-schema data. Before an explicit restore, normal lifecycle, onboarding, automation, and local-control writes are disabled. The original bytes are preserved as a private local recovery copy when an explicit restore is confirmed, under ~/Library/Application Support/CodePulse/Backups/Unreadable State ...json.

Restore is local-only and does not contact a cloud service. Session Automation is restored but left disabled until it is reviewed and deliberately enabled again. A backup moved to another Mac may contain project names and saved folder-path snapshots whose security-scoped bookmarks no longer resolve; those projects remain in CodePulse and are marked Needs Relink rather than being deleted or silently bound to another folder. Restore is blocked while the current installation has any running, paused, or finishing Session or relevant per-Session Git capture in progress.

CSV and Markdown exports

Use History → Export CSV… to save exactly the completed sessions matching the current History search and filters. The export uses standard UTF-8 CSV and a user-selected local destination; an active session is not included.

Use Insights → Export Report… to save the currently selected timeframe and project as a deterministic Markdown report. The report uses the existing local Insights summary, including Project Outcomes and Focus Patterns. Project Outcomes may include the bounded user-authored Goal/Actual text shown in the current view because you explicitly chose the export; this text is not added to notifications or uploaded, and the report contains no AI-generated commentary.

Both exports are created locally at the destination you choose. CodePulse does not upload CSV or Markdown exports.

Local daily and weekly digests

Settings → Data → Actionable Insights offers opt-in daily and weekly digests (disabled by default). A digest summarizes the previous completed local calendar day or week — active time, session count, top project and work type, and Codex/OpenCode participation, with a comparison to the preceding equivalent period. Digests may also include an aggregate follow-up count when completed sessions with goals are missing outcomes. They are delivered as native macOS notifications at a time you choose.

Everything is computed on this Mac from the same local Insights data; digests use no network, account, or cloud service. Notifications contain only aggregate metrics, follow-up counts, and project names — never session goals or outcomes, file paths, repository URLs, branches, or pull-request titles. macOS asks for notification permission only when you first enable a digest, and CodePulse keeps working normally if you decline. A digest period is delivered once, even across relaunches.

Project archiving

Use Settings → Projects → Archive when you want to retire a project without deleting its CodePulse data. Archived projects are excluded from new-session pickers, Quick Start, default-project selection, Session Automation, and direct codepulsectl starts. CodePulse keeps the project record and does not rewrite completed sessions.

Archived projects remain available in History and Insights, including History CSV and Insights Markdown exports. Session Presets and automation rules that reference an archived project are preserved and shown as unavailable until the project is restored. Use Restore in Settings → Projects to make the same project, preset, and rule eligible again. Archive state is part of local backup configuration and is independent from Needs Relink folder status.

External local control

codepulsectl is a small local controller. It talks to the running CodePulse app through a versioned, CodePulse-owned local inbox and response path; it does not edit state.json, execute shell input, contact a service, or require root, Accessibility, or Screen Recording permission. The app validates each command, rejects commands older than 30 seconds, and records a bounded UUID ledger so a replayed command cannot run twice.

The preferred form starts a configured Session Preset by its unique name:

/Applications/CodePulse.app/Contents/Helpers/codepulsectl status
/Applications/CodePulse.app/Contents/Helpers/codepulsectl status --json
/Applications/CodePulse.app/Contents/Helpers/codepulsectl start --preset "CodePulse Coding"
/Applications/CodePulse.app/Contents/Helpers/codepulsectl pause --session-id <uuid>
/Applications/CodePulse.app/Contents/Helpers/codepulsectl resume --session-id <uuid>
/Applications/CodePulse.app/Contents/Helpers/codepulsectl finish --session-id <uuid>

UUID targeting is preferred. A no-ID lifecycle mutation is invalid with zero eligible Sessions, works with exactly one eligible Session, and is rejected as ambiguous when more than one Session is eligible. The CLI does not add codepulsectl save, discard, or outcome commands; those remain in-app SessionStore/UI operations. See the normative specification.

Direct manual start is also available when the project already exists in CodePulse:

/Applications/CodePulse.app/Contents/Helpers/codepulsectl start \
  --project "CodePulse" --type coding --goal "Fix release verification"

CLI starts are manual sessions. CLI pause, resume, and finish behave like the corresponding UI actions and take over an automatic session permanently for that session. finish enters the normal finishing screen and does not save an outcome automatically; save or discard it from the CodePulse UI.

status prints concise human-readable state. status --json prints only a privacy-minimal versioned JSON status object. The command exits nonzero for invalid arguments, an unavailable app, invalid state transitions, missing or ambiguous presets/projects, expired/rejected commands, and local transport failures. A response timeout is exit code 7; a mutation may already have been applied, so re-read status before retrying. The embedded tool is not installed into /usr/local/bin; add a shell alias or use its bundle path explicitly.

Local data and privacy

CodePulse stores its state as JSON under the user's Application Support directory. Session notes, project paths, settings, session presets, automation rules, configured application bundle identifiers, active automation ownership, Git snapshots, GitHub context snapshots, developer-tool session metadata, and active session state stay on the Mac unless the user explicitly exports or shares selected data or a backup. Developer-tool metadata is limited to the tool name, external session identifier, working directory, timestamps, lifecycle event count, and optional model/profile labels. When Session Automation is enabled, CodePulse uses only those local lifecycle signals and the working directory to match an explicit rule to a configured project. CodePulse also keeps a local deduplication ledger of processed event identifiers and timestamps (up to 2,048 entries; event processing prunes entries older than 30 days). This replay bookkeeping remains local and is reset when a backup is restored; portable backups include saved-session developer-tool contexts but omit the processed event ledger. External CLI commands use a separate bounded local processing ledger and transient response files; backup export intentionally omits that control ledger and all command/response files. Inbox cleanup after processing is best effort, so a filesystem failure may leave a local event file. CodePulse does not collect prompts, messages, responses, transcripts, source code, terminal command contents, command output, tool-call arguments or results, permission decisions, reasoning, conversation summaries, or credentials. Application automation, when explicitly enabled, observes only which application is frontmost and compares its bundle identifier with local rules. In v1.5, a separate bounded retired-Thread ledger protects recently completed/discarded Developer-Tool identities for seven days; it is local processing metadata, omitted from portable backups, and reset on restore. CodePulse does not collect or retain application usage history, unrelated-app durations, window titles, document or file names, browser URLs, screen contents, keystrokes, mouse input, clipboard contents, or accessibility element contents.

Sparkle checks CodePulse release assets on GitHub. When gh is installed, the optional GitHub Context feature uses the user's existing GitHub CLI setup for read-only repository and pull request metadata. CodePulse does not store GitHub credentials, and sessions still work without gh. See PRIVACY.md for the data-handling summary and SECURITY.md for vulnerability reporting and the security model.

Build from source

CodePulse is a Swift Package Manager application. On macOS with Xcode or a Swift toolchain installed, run:

./script/build_and_run.sh

The script builds the package, stages a real app bundle, and launches it with the macOS open command. To verify that the process starts:

./script/build_and_run.sh --verify

For release packaging, use ./script/package_release.sh and follow docs/releasing.md.

README screenshots are rendered from the real SwiftUI views with deterministic, privacy-safe sample data. Regenerate them with:

./script/generate_readme_screenshots.sh

Design notes

In v1.5, SessionStore owns a bounded collection of independently identified running, paused, or finishing Sessions. Session duration is derived from timestamps and pause intervals rather than an incrementing counter, which keeps recovery and calendar-boundary calculations stable. The canonical state is a bounded collection of independently identified Sessions; the selected Project and Workspace remain presentation/organization context, not Developer-Tool Thread identity.

When a selected project is inside a local Git working tree, CodePulse reads the repository root, branch, HEAD, and diff statistics at session boundaries. Git capture is best-effort and read-only: failures never interrupt timing or saving. Historical Git metadata is preserved when a completed session is edited.

CodePulse 0.5 adds GitHub Context for GitHub-hosted repositories: it can record the normalized owner/repository identity and the pull request associated with the session's branch. This enrichment is read-only, asynchronous, and failure-tolerant. It uses the locally installed GitHub CLI (gh) when available; an authenticated gh enables private repository and pull request metadata. CodePulse never asks for or stores GitHub credentials and never sends session notes, timing, file contents, or working-tree data to GitHub.

To inspect the optional CLI status yourself, use:

gh auth status

CodePulse 0.6 adds optional Developer Integrations for Codex and OpenCode. A small local helper writes validated, versioned events to the CodePulse-owned inbox at ~/Library/Application Support/CodePulse/Integrations/Inbox/. CodePulse associates an event with its exact Thread-owned Session after the canonical working directory resolves to that Session's Project folder or a child directory. A Developer-Tool external session ID is retained as participation metadata, not as a replacement for Project identity. No Project sessions and unrelated Projects are ignored; Integration context enrichment remains independent from Session Automation. The v1.5 routing rules allow multiple independent Thread owners and are defined in docs/v1.5-concurrent-sessions.md.

CodePulse 0.8 adds optional Session Automation for Codex, OpenCode, and explicit frontmost-application rules. Session Presets hold reusable project, work type, and goal values; automation rules reference presets by stable ID. In the current v1.5 implementation, matching developer-tool lifecycle signals can start independent Thread-owned Sessions, while a configured application bundle can start at most one application-owned Session; later claims can keep it alive, resume an automatic pause, and finish and save it after the configured grace periods. Existing active Sessions are never switched to another Project, manual lifecycle actions take control immediately, and neither app activation changes nor raw event files are retained as an activity history. The global automation setting is off by default. codepulsectl adds bounded local manual control for status and UUID-targeted Session lifecycle; it does not add a cloud API, webhook, or network control path. v1.5 scopes those lifecycle claims, deadlines, and saves to independent Session UUIDs without broadening application-trigger semantics.

CodePulse 0.7 adds Session Intelligence to Insights. It derives active-time metrics from the existing local session history, supports calendar and rolling timeframes plus project filtering, and shows participation-based developer-tool counts, optional model/profile labels, neutral Git Activity totals, and historical GitHub repository and pull-request context. These are local derived views only: CodePulse does not add an analytics database, upload analytics, or measure productivity.

History filters before grouping sessions by day and searches existing project, journal, GitHub, and developer-tool metadata. Insights uses the user's local calendar, apportions active time across day and week boundaries while excluding pauses, and keeps historical GitHub snapshots unchanged.

Tests

Run the deterministic SwiftPM test suite with:

swift test --configuration debug

Tests use injected clocks and calendars, so timer, relaunch, history, Git, GitHub, Insights, and backup behavior can be verified without sleeping.

License

CodePulse is available under the MIT License.

About

A native macOS app for tracking coding sessions, project time, and developer-tool activity — local-first, private, and built to stay out of your way.

Resources

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages