Skip to content

schnaq/conan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Conan

A macOS menu-bar time tracker for working several projects in parallel — built for the "one main project, agents running, you pick up side work in the gaps" workflow. Conan layers on top of watson: everything it tracks lands in watson, so watson report --day keeps working as before.

How it works

  • Main project is tracked 1:1, exactly like watson today (1h worked → 1h tracked).
  • Side projects accrue a percentage of main time while switched on, additively (main keeps its full hour; the side time is extra). 10% → every hour on main adds 6 min. Forward-only: a side project accrues only from the moment you start it.
  • Stop the main project (stops everything) or any side project individually.
  • Conan owns all timing and appends completed frames straight into watson's frames file when intervals close (no watson binary or Python needed). Side frames are tagged +conan so you can spot them in watson report/watson log.
  • Terminal-aware: Conan keeps watson's running-frame state in sync, so watson start <project> in the terminal shows up in Conan (marked started in terminal) and watson stop stops it there too. The running frame is closed exactly once — by whoever stops it, Conan or the CLI — so time is never double-counted. While a session is running the frame is "taken", so a second terminal watson start is refused until you stop.
  • Tags set on a project (main or side) pass straight through to watson's frames and show up in the daily summary's per-tag breakdown.
  • A live today report (from watson report --day --json) shows committed time, broken down by project and tag. The in-progress session is written to watson when you stop it.

Requirements

  • macOS 13+ (uses SwiftUI MenuBarExtra)
  • No external dependencies. Conan reads and writes watson's data file (~/Library/Application Support/watson/frames) directly, so a watson install is optional. If you do have the watson CLI, Conan shares its data — watson report --day keeps working alongside Conan, and vice versa.

Build & run

swift test            # run the unit tests
./scripts/build-app.sh   # build + assemble + ad-hoc sign Conan.app
open Conan.app           # launch (menu-bar only, no dock icon)

To sign with your own identity: SIGN_IDENTITY="Apple Development: …" ./scripts/build-app.sh. Install by copying Conan.app to /Applications. To start at login, add it under System Settings → General → Login Items.

Distribution (signed + notarized DMG)

build-app.sh ad-hoc signs, which only runs cleanly on the build machine. To hand the app to other Macs without Gatekeeper warnings, scripts/release.sh builds a universal (arm64 + x86_64), Developer-ID-signed, notarized, stapled dist/Conan.dmg.

One-time setup (needs a paid Apple Developer Program membership):

  1. Create a Developer ID Application certificate — Xcode → Settings → Accounts → your team → Manage Certificates → + → Developer ID Application. (This is different from the "Apple Distribution" cert used for the App Store / iOS.) Find its name with security find-identity -v -p codesigning | grep "Developer ID Application".

  2. Create an app-specific password at appleid.apple.com (or an App Store Connect API key).

  3. Store notary credentials once (Team ID must match the cert):

    xcrun notarytool store-credentials "conan-notary" \
      --apple-id "you@example.com" --team-id "TEAMID" --password "app-specific-password"

Then build the release:

DEV_ID="Developer ID Application: Your Name (TEAMID)" ./scripts/release.sh
# → dist/Conan.dmg  (signed, notarized, stapled, universal)

Recipients double-click the DMG and drag Conan to Applications — no warnings. SKIP_NOTARIZE=1 produces a signed-but-not-notarized build for local inspection.

Cutting a versioned GitHub release

scripts/publish.sh wraps the whole flow: it auto-detects your installed Developer ID identity, stamps the version into Info.plist, builds the notarized DMG (via release.sh), then commits the version bump, tags, pushes, and creates a GitHub release with the DMG attached.

./scripts/publish.sh 0.2.0      # needs a clean working tree; a leading "v" is fine too

DRY_RUN=1 ./scripts/publish.sh 0.2.0 builds and previews everything without committing, tagging, pushing, or releasing.

Auto-update (Sparkle)

Conan self-updates via Sparkle. It reads the appcast at https://github.com/schnaq/conan/releases/latest/download/appcast.xml, and when a newer build is published it downloads, verifies (EdDSA + Developer ID), installs, and relaunches — gated by the Automatically check for updates toggle, with a manual Check for Updates… button in the popover footer. Sparkle compares the monotonic CFBundleVersion.

publish.sh handles the release side: it generates an EdDSA-signed appcast.xml (via Sparkle's generate_appcast) pointing at the new DMG and uploads it alongside Conan-X.Y.Z.dmg. scripts/embed-sparkle.sh embeds + inside-out-signs Sparkle.framework into the bundle (called by both build-app.sh and release.sh before the app is signed).

One-time setup (already done for this repo): a Sparkle EdDSA key pair was created with generate_keys — the private key lives in the login keychain (needed by publish.sh), and the public key is in Info.plist as SUPublicEDKey.

Usage

  1. Click the menu-bar timer. Type a project (or pick a recently-used project/tag variant — or any known project — from the chooser), add optional space-separated tags, and Start.
  2. Add side projects with a percentage and optional tags; each shows its live accrued time.
  3. Stop all ends the session; stop a single side project to close just that one.
  4. Open the popover any time to see today's totals, broken down by project and tag.

You can also watson start/watson stop from the terminal — Conan picks the change up automatically (instantly when you open the popover, otherwise within ~30 s).

Settings

In the popover footer:

  • Start at login — registers Conan as a macOS login item (SMAppService).
  • Remind me when I'm not tracking — while Conan is running, if you've been active at the Mac for 5 minutes with no project tracked, it posts a notification nudge. It fires once per active streak and re-arms after you start tracking or step away from the Mac. Requires notification permission (requested when you enable it).
  • Automatically check for updates — Conan checks GitHub for newer releases (via Sparkle) and offers to install them. Use Check for Updates… for a manual check.

Data

  • Conan stores its in-flight session at ~/Library/Application Support/Conan/state.json (dates as epoch seconds) and replays it on launch after a crash, flushing tracked time up to the last 30-second heartbeat.
  • The running session is mirrored into watson's own state file (~/Library/Application Support/watson/state) to keep the watson CLI in sync. On launch Conan reconciles the two: if watson stop ran while Conan was closed, the main frame watson already wrote is not re-counted (only side-project time is flushed).
  • Finished time is appended directly to watson's frames file (same JSON format watson uses), so the watson CLI reads it natively — no separate watson install required.

About

A watson-based timetracker for parallel projects.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors