Skip to content

Team Tracker

Team Tracker records active minutes in 5-minute blocks while you work in VS Code or Cursor, classifies them per team workspace as internal or external based on the Git remote of the active editor, and sends aggregates to the SnakeFlow team API. It is optional and off until you sign in and enable it.

Minute counting is independent of Wake Lock → (OS sleep prevention): the tracker does not infer “human active” from whether the wake lock is held.

Requirements

  • SnakeFlow: Team Tracker — Login (GitHub OAuth via the editor).
  • devManager.team.enabled set to true (the login command can turn this on for you).

Activity sources

The tracker uses native OS APIs — no external tools required on Windows, macOS, or Linux X11.

PlatformNative supportWhat you get
Windows 10/11✅ Built-inGetForegroundWindow + QueryFullProcessImageName + GetWindowTextW via PowerShell
macOS✅ Built-inSystem Events (app name); window title requires Accessibility permission (see below)
Linux X11xdotoolApp class + window title. Install: apt install xdotool / dnf install xdotool / pacman -S xdotool
Linux Wayland (GNOME)⚠️ Extension neededInstall Focused Window D-Bus shell extension
Linux Wayland (Sway)✅ Built-inswaymsg -t get_tree — detected via SWAYSOCK env variable
Linux Wayland (Hyprland)✅ Built-inhyprctl activewindow — detected via HYPRLAND_INSTANCE_SIGNATURE env variable
Linux Wayland (other)❌ Not supportedFalls back to VS Code focus + repo classification only (no regression from previous behaviour)

Control the active-app source with devManager.team.activeAppSource:

  • native (default) — native OS API for app name and window title.
  • off — no active-app data; VS Code focus + repo patterns only.

macOS Accessibility permission

When Accessibility is not granted, the macOS provider still reports the app name but cannot read window titles. To enable full title tracking:

  1. Open System Settings → Privacy & Security → Accessibility.
  2. Enable the entry for Cursor or VS Code.
  3. Run SnakeFlow: Team Tracker — Re-check Accessibility Permission (Command Palette).

A one-time notification appears on first run when permission is not yet granted.

What counts as “active”

Each 5-minute tick first checks the optional Sleep window (forces IDLE if local time falls inside idleSleepWindow). A successful tick credits 5 minutes of internal time.

The collector then evaluates two signals:

SignalSourceRole
OS idleWindows GetLastInputInfo, macOS HIDIdleTime, Linux xprintidle / Mutter D-Bus / org.freedesktop.ScreenSaverPrimary — true last user input age; robust against synthetic hooks.
IDE focusVS Code window.state.focused + last focus timestamp (aggregated across all your editor windows)Corroborates OS signal when an editor window had OS focus recently.

A tick refreshes the activity clock only when trustworthy evaluates true — i.e. one of:

  1. OS alone (Windows / macOS)GetLastInputInfo / HIDIdleTime cannot be spoofed by LL hooks.
  2. OS + recent IDE focus — OS reports recent input and an editor window had OS focus within the idle window.
  3. OS alone (Linux)xprintidle, Mutter D-Bus, or org.freedesktop.ScreenSaver reports recent input.
  4. Linux pattern fallback — no OS idle API available (e.g. COSMIC, or missing xprintidle) and a focused editor window matches the workspace repo patterns.

If none of the above apply for longer than your effective idle window, the tick is IDLE (no increment). The client uses the minimum idle_window_minutes from all team workspaces you belong to (server-side admin setting). With no workspace memberships yet, a built-in default applies until you join.

Multiple windows

Only one editor window per machine is the leader and counts time (this avoids double-counting). To support tiling / multi-window setups, every window publishes its focus and active repo to a shared file, and the leader credits internal time whenever any of your windows is focused on a matching repo — even if the focused window is not the leader itself. Followers show the leader-counted today total with a tracking elsewhere badge and a Track in this window action to force leadership here.

Each UTC day is capped by the backend: 1440 internal minutes per member/workspace/day and 60 minutes per UTC hour (heatmap). See Cloud API → limits.

What counts

Team Tracker records internal time only — minutes when you are actively working in a focused editor window on a repo that matches the workspace repo patterns (glob-style lists configured per workspace; see Cloud sync → Repo patterns).

For each workspace you belong to, a tick adds +5 internal minutes only when all of the following are true:

  1. Activity gate — at least one trustworthy activity branch fired (see What counts as active).
  2. Editor focus — some SnakeFlow/Cursor/VS Code window of yours has OS focus (including follower windows via the shared focus file — see Multiple windows).
  3. Repo match — the current GitHub-style remote of the active text editor (owner/repo) matches that workspace’s repo patterns. Empty pattern list means “allow all repos”.

If any condition fails, the tick is skipped — no minutes are stored for that workspace. There is no external time bucket; wrong repo, unfocused editor, or idle beyond the window simply means zero credit.

Note: Repo classification always uses the focused editor’s remote. Keep a relevant file focused when you care about correct workspace routing.

App allowlist (admin)

Workspace admins maintain the list of regex strings on the server:

  • SnakeFlow CloudTeam tab → workspace toolbar → Edit app allowlist (camera icon), which opens the same flow as the command below.
  • SnakeFlow: Team Tracker — Edit App Allowlist (Command Palette) — comma-separated regexes; leave empty to clear the list (allow all apps again).

The server validates each pattern as a JavaScript RegExp (case-insensitive flag) and rejects invalid syntax. Hard limits: 50 repo patterns per workspace, 200 characters per pattern — see Cloud API → limits and Team routes.

Tip: Patterns are matched against both the executable / app name and the window title (for example Cursor or \.tsx in the title).

Settings

SettingTypeDefaultDescription
devManager.team.enabledbooleanfalseMaster switch for Team Tracker.
devManager.team.activeAppSourcestring"native"Active-app source: native or off. See Activity sources.
devManager.team.idleWindowMinutesnumber5Declared idle window in Settings (1–15); changing it restarts the collector. Effective detection is clamped to 5–10 minutes client-side; the active value is the minimum server idle_window_minutes across your workspaces — see What counts as active.
devManager.team.dayGoalMinutesnumber360Target minutes for the status bar tooltip progress bar (default 6h). Visualization only — does not change how minutes are counted. See Day goal.
devManager.team.requireTrackingbooleanfalseWhen true, warn if tracking is off and no session started.
devManager.team.idleSleepWindowstring""Local-time HH:MM-HH:MM window during which tracking is force-IDLE — see Sleep window.

Changing enabled, activeAppSource, idleWindowMinutes, or idleSleepWindow triggers a collector restart so new values apply without reloading the window. dayGoalMinutes only affects the status bar tooltip.

Day goal

devManager.team.dayGoalMinutes (60–720, default 360 = 6 hours) sets how full the ▓░ progress bar looks in the Team Tracker status bar tooltip. Hover the $(watch) item to see today’s internal minutes, the bar, and _(goal: …)_. This does not cap or alter minute counting — only the visual reference for your workday target.

Sleep window

devManager.team.idleSleepWindow (format HH:MM-HH:MM in local time, default empty) is a belt-and-braces guard against false-positive activity at night. While the current local time falls inside this interval, the collector forces IDLE regardless of any activity signal.

Use it when:

  • Synthetic input from remote-control or “anti-idle” tools (AnyDesk, mouse jigglers, certain drivers) misleads tracking into reporting activity while you sleep.
  • A long-running task or never-released wake lock keeps the OS awake overnight.

The window wraps over midnight when end < start — 23:00-07:00 covers a typical sleep schedule. Empty string disables the override.

Commands

CommandDescription
SnakeFlow: Team Tracker — LoginSign in; can enable team tracking.
SnakeFlow: Team Tracker — LogoutStop tracking and sign out.
SnakeFlow: Team Tracker — StatusFull diagnostics report in the activity log.
SnakeFlow: Team Tracker — Show Activity LogOutput channel with per-minute reasons.
SnakeFlow: Team Tracker — Re-check Accessibility Permission (macOS)Re-probe AX permission after granting it in System Settings.
SnakeFlow: Team Tracker — Edit App AllowlistWorkspace admin: edit regex allowlist for app/title (server-side).
SnakeFlow: Team Tracker — Create WorkspaceAdmin: new workspace + invite.
SnakeFlow: Team Tracker — Join WorkspaceJoin with invite code.
SnakeFlow: Team Tracker — Manage WorkspacesList / switch context.
SnakeFlow: Team Tracker — Sync Commits (admin)Push aggregated commit counts for dashboards.
SnakeFlow: Team Tracker — Sync Closed Issues (admin)Push closed GitHub issue counts (assignee + UTC closed day) for dashboards.

Commit and closed-issue sync (admin)

Workspace admins with Team Tracker enabled and a GitHub session can sync aggregated GitHub data into SnakeFlow Cloud (D1). The backend never receives your GitHub token; the extension queries GitHub Search and POSTs counts.

MetricGitHub query (per member, per UTC day)Stored asInternal vs external
Commitsauthor:{login} author-date:{YYYY-MM-DD}daily_commitsRepo matches workspace repo patterns → internal count; otherwise external count
Closed issuesassignee:{login} is:issue is:closed closed:{YYYY-MM-DD}daily_closed_issuesSame repo patterns

These GitHub metrics are separate from time tracking — they count commits and closed issues, not active minutes.

  • Assignee required for closed issues: unassigned issues are not counted.
  • Who closed does not matter — only assignee and closed date.
  • Sync runs hourly while tracking is on (admin workspaces) and can be triggered manually via the commands above (last 7 UTC days by default).
  • SnakeFlow Cloud → Activity shows internal commit/issue counts; time columns reflect matching-repo minutes only.

Hourly heatmap and member time zones

The SnakeFlow Cloud → Activity view shows a per-day 24-hour strip (0h–23h) for each member. The backend stores hourly buckets in UTC (the hour at flush time on the server). That alone would misalign “9 AM local work” for teammates in different regions.

On every successful POST /api/team/active-minutes flush, the extension sends the member’s IANA time zone (from Intl.DateTimeFormat().resolvedOptions().timeZone, for example Europe/Kyiv). The API stores it on the workspace_members row for that member (last value wins).

The dashboard then converts each stored (UTC day, UTC hour) bucket into that member’s local calendar hour before drawing the strip. The result is a shared 0–23 “local working hours” axis: if one person starts at 09:00 in Kyiv and another at 09:00 in London, both appear in the same column (hour 9), which matches how teams usually read “who was active when” in their own heads.

  • Legacy members who have never pushed with a client that sends timezone show null in the API; the UI treats that as UTC for the conversion until their next flush updates the field.
  • Changing the OS time zone on a machine updates the value on the next push; historical buckets are reinterpreted with the latest stored zone (acceptable for a team-activity overview).
  • Per-day totals (daily_minutes) stay on UTC calendar days from the server; only the hourly visualization uses the member zone shift.

There is no separate “workspace time zone” setting for this feature—the alignment comes from each member’s reported zone.

See also