---
title: Time Tracker
---

# Time Tracker

## What it is

A built-in, **off-by-default** personal time tracker inside Omniscio. Press **Start** when you
sit down to work and a live timer runs; press **Start** again (or **Stop**) and the block
drops onto a colour-coded timeline for the day. Each block can be tagged, attributed to a
**tracker project**, and marked **billable**, and a stats strip shows today / this-week /
by-project totals plus today's billable dollar figure. Everything runs locally on your
machine — no AI, no internet, no cost.

## Where to find it

It's hidden until you enable it. Go to **Settings → Lab** and switch on **Time Tracker**.
Once on, **Time Tracker** appears as a row in the sidebar (alongside the other integrations);
click it to open the **Today** screen. It works like the other built-in virtual projects: the
panel owns the whole area beside the projects sidebar, and it works on a phone too. (Under the
hood it's gated through Omniscio's unreleased-feature registry — setting key `timeTrackerEnabled`,
default `false`.)

## How it behaves

### The Today screen

- **Start row** — type what you're working on, optionally pick a **project** and toggle
  **billable**, then press **Start**. If a timer is already running, starting a new one
  automatically **stops** the previous block and logs it (one timer at a time).
- **Running header** — while a timer runs it shows the live elapsed time and a **Stop** button.
- **Timeline** — today's blocks, newest first, each showing its description, project, duration,
  tags, and a billable marker. Hover (or tap on mobile) a row to **edit** or **delete** it.
- **Stats strip** — today's total, this-week's total, and today's **billable** dollar amount,
  plus a per-project breakdown.
- **Projects** — each tracker project carries a colour, an hourly **rate**, a **billable**
  default, and an optional link to a real Omniscio project. You can create one inline from the
  Start row.

### Money

You set an hourly **rate** on a project; entries store no dollar amount of their own. The
billable figure is **derived** — hours on the clock × the project's rate — and rounded once
per project when the stats are computed, so the totals never drift by a penny. The tracker's
dollars are your own invoicing figures and are kept completely separate from Omniscio's AI-spend
tracking.

### The runaway-timer guard

If a timer has been running an unusually long time (for example you left it on overnight or
across a restart), a banner appears so you can **Keep** it running, **Stop** it now (keeping
the time so far), or **Discard** the runaway entry — instead of silently logging 14 hours.

### Focus sessions (Pomodoro)

When you finish a **Pomodoro focus session**, it now shows up on this same timeline as a green
**focus** block, so your focus time counts toward your today / week / billable totals right
alongside your manual timers — no double entry. Your existing Pomodoro history is folded in the
first time the tracker runs, and every new focus session appears automatically when it ends.

A few details worth knowing:

- The block's length is your actual **focus time** (the completed focus minutes), not the
  wall-clock span — the breaks in between aren't counted.
- If a focus run was attributed to an Omniscio project, the block is attributed to the **tracker
  project** you linked to that Omniscio project (otherwise it lands under *Unassigned*).
- It's a one-way copy made when the session ends: your Pomodoro timer keeps working exactly as
  before, and you can edit or delete a focus block on the timeline like any other entry — your
  changes stick.
- Finishing a focus session never interrupts a manual timer that happens to be running.

### Plan vs. actual (planning ahead)

You can block out time you **intend** to spend before you do it, then see it against what you
actually logged — on the same Today screen.

- **Plan time** — press **Plan time** in the *Planned* section and pick a project, an optional
  description, a start, and a duration. That planned block shows up as a distinct **"ghost"**
  row (with a calendar-clock icon and a *Planned* marker), so you never confuse it with time
  you actually logged.
- **Plan vs. actual** — a small readout shows, for the day and per project, your **planned**
  hours next to your **actual** hours and the **variance** (how far over or under your plan you
  are). Over/under is shown plainly — going over or under isn't "good" or "bad", it's just the
  gap.
- **It's time only.** Planned time never counts as real logged time and never affects your
  billable dollars — the billable figure is still derived only from the time you actually
  track. There's no "planned earnings" number.
- **Plans and actuals stay separate.** A plan doesn't turn into a logged entry — you keep both,
  so the comparison always makes sense. Edit or delete a plan from its row like any other entry.

### Reports & export

A **Reports** tab (next to **Today**, same panel) rolls up the time you actually logged over a
date range and lets you export it.

- **Pick a range** — **Today**, **This week**, **This month**, or a **Custom** start/end day. The
  range is read in your local time, exactly like the Today timeline, so days line up.
- **See the summary** — total hours, hours **by project** (with each project's billable dollars),
  and hours **by tag**. (A block with several tags counts toward each tag, so tag hours can add up
  to more than the total.)
- **Export CSV** — two buttons:
  - **Summary CSV** — one rollup sheet: a row per project (hours, billable hours, billable $) and a
    row per tag (hours), plus a total row.
  - **Detail CSV** — one row per logged entry (date, start, end, duration, project, tags, billable
    yes/no, description, note). It carries **no dollar column** — money is never a per-entry figure.
- The files download straight to your device (desktop and phone alike). Everything stays local — no
  network, no cost.

**The money stays honest.** The billable dollars in a report or export are **derived once from your
actual entries** by the same calculation the Today stats strip uses — so a report can never disagree
with what you see on Today, and it's the same figure to the penny. Planned time and unconfirmed
entries never count toward a report's hours or dollars.

**Safe to open in a spreadsheet.** Exported cells that could be read as a spreadsheet formula (text
starting with `=`, `+`, `-`, or `@`) are neutralized so opening the CSV in Excel or Sheets can't run
anything.

### Invoices & clients

An **Invoices** tab (next to **Reports**, same panel) turns your billable hours into a saved
**invoice document** for a client.

- **Clients** — press **Clients** to add the people/companies you bill (a name, and optionally an
  email and address). A client's details are saved onto each invoice you make for them, so editing
  or removing a client later never changes an invoice you already created.
- **Projects & rates** — press **Projects & rates** to set each project's **hourly rate**, its
  **billable** default, and the **client** it bills to. (Projects are created on the Today screen;
  this is where you give them a rate and a client.) An invoice only includes projects that are
  linked to the chosen client.
- **Create an invoice** — press **New invoice**, pick a **client** and a **date range** (and an
  optional flat **tax %**). You'll see a live **preview**: one line per project with its hours and
  amount, a subtotal, tax, and total. Press **Create** to save it. It gets an **invoice number**
  (auto like `INV-2026-0001`, or type your own), a **date**, and starts as a **Draft**.
- **View / status / export** — open an invoice to see the document. Move it through **Draft →
  Sent → Paid** (in any order — it's your record). **Export CSV** downloads it. You can **delete**
  it (it's removed from the list).
- **Drafts can be refreshed; finalized invoices are locked.** While an invoice is a **Draft** you
  can press **Regenerate** to pick up time you logged after creating it. The moment you mark it
  **Sent** or **Paid**, its amounts are **locked permanently** — a later edit to your time entries
  can never change a finalized invoice. That's what makes it a trustworthy record.

**The money stays honest here too.** An invoice's amounts are computed from your **actual billable
entries** by the exact same calculation as the Reports tab and the Today stats — so an invoice can
never disagree with what you see elsewhere, to the penny. It's kept completely separate from Omniscio's
own AI-spend tracking.

### Auto-capture (suggested entries)

**Off by default.** If you'd rather not start and stop timers by hand, auto-capture can watch
what you work on and **suggest** entries for you to review — so you barely touch a timer. Turn it
on in the **Review** tab (next to Invoices): switch on **Suggest entries from my activity**.

- **How it works** — while it's on, Omniscio notices which app you're using and for how long, and
  turns each stretch of work into a **suggested** entry. Suggestions collect on the Review tab;
  nothing is logged for you automatically.
- **You stay in control (confirm-first)** — a suggestion is only a draft. It does **not** count
  toward your timeline, stats, billable dollars, reports, or invoices until you **accept** it.
  Accepting adds it to Today (where you can give it a project); **Discard** deletes it for good.
- **What it records** — the **app name** and how long you were in it, plus idle gaps. If you want
  more detail you can separately turn on **Also capture window titles** — a title can include a
  document or email subject, so it's a deliberate second opt-in, off by default. It **never**
  records your keystrokes, screen contents, clipboard, or documents; no screenshots, no page
  content, no browser URLs.
- **Everything stays on your computer** — captured activity is never uploaded, logged, sent to
  telemetry, or synced, and it isn't sent to your phone (auto-capture is desktop-only). Discarding
  a suggestion really deletes it, and any suggestion you don't act on is cleared automatically
  after **7 days**.
- **Tune it** — set how long a gap of no activity ends a block (the **idle** threshold, default
  5 minutes).
- **Windows only for now** — auto-capture runs on Windows in this version; elsewhere the Review
  tab simply won't collect suggestions.

### Not in this version

This version is a **manual** tracker plus the Pomodoro focus bridge, plan-vs-actual planning, the
reports/CSV export, the invoices/clients, and the opt-in auto-capture above. Recurring/repeating
plans, reminders, a formatted **PDF** invoice/report, taking payment, automatic tax by region,
multiple currencies, recurring invoices, emailing an invoice, and smarter auto-capture (categorising
activity, macOS/Linux, per-tab detail) are planned follow-ups — the data model is shaped for them,
but nothing drives them yet.

### Privacy & cost

100% local. Your entries — and anything auto-capture records (app names, and window titles only if
you opt in) — are saved **only** in Omniscio's local database; nothing is sent anywhere, logged, or
synced, and no AI/network calls are made, so it costs nothing to use.

### Limitations (this version)

Manual timers, the Pomodoro focus bridge, plan-vs-actual planning, range reports with CSV export,
invoices/clients, and opt-in **auto-capture** (Windows-only, confirm-first, app-name + optional
window-title only); no activity categorising, no macOS/Linux capture, no recurring/repeating plans,
no reminders, no PDF, no payment/tax-by-region/multi-currency/recurring/emailing of invoices yet.

## For agents

### Under the hood (for agents)

- **Schema** — migration
  [20260718034022-add-time-tracker-tables-projects-tags-entries-entry-tags.ts](../../src/main/db/migrations/20260718034022-add-time-tracker-tables-projects-tags-entries-entry-tags.ts):
  `tracker_projects`, `tracker_tags`, `time_entries` (the unified timeline — one row per block),
  `entry_tags` (junction). Money is an exact integer micro-USD column on the project rate (no
  float); non-negative triggers guard the rate + duration; `source` is a closed CHECK enum
  (`manual` / `focus` / `planned` / `auto`).
- **DB layer** — [src/main/db/queries-time-tracker/index.ts](../../src/main/db/queries-time-tracker/index.ts):
  CRUD + the timer lifecycle (single-running auto-stop, duration clamped ≥ 0) + the today/week/
  by-project stats with the derive-once billable math + runaway-timer detection.
- **IPC** — `time-tracker:*` channels (projects / tags / entries / running / stats / stale),
  typed + Zod-validated; every mutation emits `time-tracker/changed` so any client reloads.
- **UI** — [src/renderer/src/features/time-tracker/](../../src/renderer/src/features/time-tracker/)
  + the Zustand store `time-tracker-store.ts`. `TimeTrackerPanelHost` is the `panelOwnsLayout` +
  `mobilePrefersPanel` Today screen.
- **Focus bridge (Slice 2)** — [src/main/services/time-tracker/focus-session-bridge.ts](../../src/main/services/time-tracker/focus-session-bridge.ts)
  observes the `POMODORO_RUN_ENDED` push + runs a startup reconcile, projecting completed
  Pomodoro runs into `source='focus'` entries. Idempotent + INSERT-ONLY on the `focus_run_id`
  link column (migration `20260718173857-…`); resolves the run's Omniscio project → a tracker project
  via `tracker_projects.amc_project_id`. Read-only against Pomodoro (all I1–I8 hold).
- **Plan vs. Actual (Slice 3)** — planned blocks are reserved `source='planned'`,
  `is_confirmed=0` entries with a real start + end (so the existing timeline/stats/billable/timer
  queries skip them for free — **no migration**). DB: `createPlannedEntry` / `updatePlannedEntry`
  / `deletePlannedEntry` / `listPlannedEntriesForDay` / `getPlanVsActual` (variance, time only) in
  [queries-time-tracker/index.ts](../../src/main/db/queries-time-tracker/index.ts). IPC: `time-tracker:plan-*`
  channels (create/update/delete + a `plan-day` read returning `{ planned, variance }`). UI:
  `PlanVsActualCard` / `PlannedEntryRow` / `PlanEditSheet` on the same Today screen.
- **Reports + Export (Slice 4)** — a range rollup + CSV export, READ + FORMAT only (**no migration**).
  DB: `getRangeReport(from,to)` + `listEntriesForRange(from,to)` in
  [queries-time-tracker/index.ts](../../src/main/db/queries-time-tracker/index.ts), reusing the exported
  derive-once `billableMicroFor` so a report's billable $ equals `getTrackerStats` to the micro-dollar
  (actual entries only; planned/unconfirmed/running excluded). Service:
  [time-tracker-report.ts](../../src/main/services/time-tracker/time-tracker-report.ts) — local-midnight
  range resolution, a formula-injection-safe CSV builder, and the detail (no-$) / summary CSVs. IPC:
  `time-tracker:report-get` (read) + `time-tracker:export-csv` (returns `{ filename, csv }` the renderer
  downloads via the shared `downloadFile`). UI: `ReportsView` on a `SegmentedControl` tab of
  `TimeTrackerPanelHost`. PDF export + a range plan-vs-actual roll-up were deferred.
- **Invoices + Clients (Slice 5)** — turns billable hours into an immutable invoice DOCUMENT.
  A NEW migration adds `tracker_clients`, `tracker_projects.client_id`, `tracker_invoices`,
  `tracker_invoice_items` (money as integer micro-USD + non-negative triggers + a `finalized_at`
  one-way-lock trigger). DB:
  [queries-time-tracker-invoices.ts](../../src/main/db/queries-time-tracker-invoices.ts) —
  `buildInvoiceSnapshot` REUSES `getRangeReport`'s per-project `billableMicroUsd` (so an invoice
  can't disagree with Reports — agreement by construction), `createInvoice` persists the snapshot,
  `regenerateInvoice` recomputes a never-finalized draft (Model B), `updateInvoiceMeta` edits
  metadata only. Service:
  [time-tracker-invoice.ts](../../src/main/services/time-tracker/time-tracker-invoice.ts) (the
  injection-safe invoice CSV). IPC: `time-tracker:client-*` + `time-tracker:invoice-*`. UI:
  `InvoicesView` + `InvoiceCreateSheet` / `InvoiceDetailSheet` / `ClientManagerSheet` /
  `ProjectManagerSheet` on a `SegmentedControl` tab. Payments, PDF, auto-tax, multi-currency,
  recurring, and emailing were deferred.
- **Auto-capture (Slice 6)** — a local, opt-in activity observer that PROPOSES confirm-first draft
  entries (**no migration** — `source='auto'` was reserved in Slice 1). A proposal is `source='auto'`,
  `is_confirmed=0`, so it is invisible to the timeline/stats/billable/reports/invoices until accepted
  (identical to a plan). DB: `createAutoProposal` / `listAutoProposals` / `confirmAutoProposal` +
  **hard-delete** `discardAutoProposal` / `deleteStaleAutoProposals` (7-day retention) in
  [queries-time-tracker/index.ts](../../src/main/db/queries-time-tracker/index.ts). The observer is a PURE
  segmenter [activity-proposer.ts](../../src/main/services/time-tracker/activity-proposer.ts) +
  the service [activity-observer.ts](../../src/main/services/time-tracker/activity-observer.ts)
  (active window via `get-windows` `activeWindow()` + idle via `powerMonitor` on a `createPeriodicTask`
  poll; Windows-first; fail-open; **never logs a title**). Gated by a startup task + a live settings
  side-effect (`reconcileActivityObserver`) + a wired teardown. Settings `timeTrackerAutoCaptureEnabled`
  / `timeTrackerAutoCaptureTitles` / `timeTrackerAutoCaptureIdleMinutes` (all default-off/5). IPC:
  `time-tracker:auto-list` (read) + `auto-confirm` / `auto-discard` (mutations) — **all three are
  web-access-denylisted (desktop-only)** so captured activity never leaves the box. UI: `ReviewView`
  + `ProposalRow` on a "Review" `SegmentedControl` tab. Privacy is locked by two dedicated guards
  (no captured activity in logs / no egress sink; all channels denylisted).
- **Mission Control bridge (hub-spoke #3)** — links PM items to time entries so users can start/stop
  timers from a Mission Control item card's **Time tab** without switching panels. Migration adds
  `pm_item_id` + `pm_item_name` (denormalized `labels-carry-entity-names` pattern) to `time_entries`. DB:
  `listEntriesForPmItem` / `getTotalTimeForPmItem` (derive-once money) in
  [queries-time-tracker/index.ts](../../src/main/db/queries-time-tracker/index.ts). IPC:
  `time-tracker:pm-entries` / `time-tracker:pm-total` (read-only, web-access-blocked). Bridge:
  5 methods on `window.__AMC_MISSION_CONTROL_SESSION__` (startTimerForItem / stopTimer / getRunningTimer /
  getTimeForItem / getEntriesForItem) installed by `MissionControlPanel.tsx`, exported by
  [session-bridge.ts](../../src/plugins/mission-control/web/lib/session-bridge.ts). UI:
  [TimeTab.tsx](../../src/plugins/mission-control/web/features/board/TimeTab.tsx) (timer control + entries
  list + summary strip) + PM item name chip on `TimelineEntryRow`. All Time Tracker invariants
  (single-running, derive-once money, confirm-first) preserved — the bridge reuses the existing
  start/stop channels. Contract:
  [pm-time-tracker-bridge-contract.md](../../.claude/memory/contracts/pm-time-tracker-bridge-contract.md).
- **Invariants** — [.claude/memory/contracts/time-tracker-contract.md](../../.claude/memory/contracts/time-tracker-contract.md)
  (single-running, derive-once money, confirm-first, runaway guard, soft-delete, closed source
  enum, the `focus-*` projection invariants, the `planned-*` / `plan-vs-actual-time-only`
  invariants, the `invoice-*` money-agreement / snapshot-immutable / Model-B-lock invariants, and
  the `auto-*` local-only / minimal-capture / confirm-first / erasable-hard-delete invariants).

## Related

Because the tracker deliberately reuses other surfaces, its closest neighbours are [Pomodoro](pomodoro.md) — whose finished focus sessions appear on the Time Tracker timeline as green focus blocks — and [Mission Control and Time Tracker](pm-time-tracker-bridge.md), which starts and stops timers from a PM item card's Time tab. The dollar figures it derives are its own invoicing numbers, kept separate from the AI-spend presented in [Stats](stats.md), and the Lab toggle that switches the whole feature on is described on [Open settings](open-settings.md).
