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.
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.
- 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
codepulsectlcommand 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.
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.
- Click the CodePulse item in the menu bar.
- Optionally choose a project and work type, then describe the session goal.
- Start the session and pause or resume it as needed.
- Finish the session, record an optional outcome, and save it to History.
- Open History to search, filter, or edit saved sessions, or open Insights to review local activity and context-derived summaries.
- 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.
- 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.
- 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.
- For a shell, Shortcuts Run Shell Script, Raycast, Alfred, Stream Deck, or
IDE task, use the bundled
codepulsectlcommand 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.
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….
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.
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.
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.
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.
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.
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.
CodePulse is a Swift Package Manager application. On macOS with Xcode or a Swift toolchain installed, run:
./script/build_and_run.shThe 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 --verifyFor 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.shIn 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 statusCodePulse 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.
Run the deterministic SwiftPM test suite with:
swift test --configuration debugTests use injected clocks and calendars, so timer, relaunch, history, Git, GitHub, Insights, and backup behavior can be verified without sleeping.
CodePulse is available under the MIT License.



