Deski

Documentation

Deski is a local-first desktop time tracker. It quietly notices when you're active at your computer and turns that into time blocks, charts and tags — and your activity data stays on your device. This page covers everything: installing, your account, every screen, and every setting.

Getting started

Install

  1. Download the Windows installer from the download page and run it.
  2. Windows SmartScreen may warn you on first run while builds are unsigned. Click More info → Run anyway.
  3. Follow the installer; Deski starts when it finishes.

Sign in

  1. On first launch, enter your email address. No password — Deski emails you a 6-digit code instead.
  2. Enter the code (it's valid for 15 minutes; you can request a new one).
  3. That's it. By signing in you agree to Deski's Terms & Conditions and Privacy Policy.

One account works on up to 3 devices at the same time — see Account, trial & billing for details.

The walkthrough

After your first sign-in, a short 4-step tour highlights the timer, your sessions, Insights and the sidebar. You can replay it anytime from Settings → Account → Tutorial → Start.

Account, trial & billing

Deski is not on sale yet. The trial and billing below describe how it will work at launch — right now access comes from the beta programme, which is 30 days and needs no card.

The window

Timer & tracking modes

Auto mode (default)

Auto records by itself — Deski watches for mouse/keyboard activity and opens a time block when you become active. The block runs until it holds a full block length of tracked time (1 to 60 minutes, 10 by default), then completes and rolls straight into the next one. A lull longer than the idle gap (10 seconds to 5 minutes, 30s by default) stops counting as tracked time and closes the block early. There's nothing to remember to press — the timer has no buttons unless you ask for them. An optional start/stop button and pause button (both off by default, Settings → Tracking → Timing) let you drive Auto by hand.

Manual mode

A plain stopwatch: Start opens a block, Stop saves it. Good for work away from the keyboard — meetings, calls, whiteboards. You can't switch modes while a manual session is running — stop it first.

If you only ever use Auto, you can hide the Auto/Manual switch entirely with Settings → Tracking → Track → Manual tracking.

The big circle shows elapsed time and a status pill (Idle, Tracking or In Progress).

Sessions & tags

Total Today sums today's tracked time. The Timer page shows your three most recent sessions; the rest live in Insights.

Deski's Tags settings page listing nine coloured tags, a new-tag field, a colour palette with a hex box and a row of saved-colour slots
Settings → Tags. Up to 100 tags, 30 characters each, with a colour per tag.

Insights

Activity chart

Pick a chart type (Heatmap or Bar) and granularity (by hour / day / month). The card's heading names whichever of the six views you are on — Weekly Pattern, Last 14 Days, Activity Calendar, Today by Hour, Last 7 Days or Last 6 Months — and the ⓘ beside it explains that view.

Bars are split by tag: the top 5 tags get their own colour, the rest group as "Other". Heatmaps shade by total time instead, so they carry no tag colours — just Less to More. Every chart reads your whole history, while the block lists show your most recent 50.

Weekly Pattern (Heatmap, by hour) is the one worth explaining: each row stacks every Monday, every Tuesday and so on that you have tracked, added together — not this week. So today's row can show time in hours that haven't arrived yet today. That is last week's work, not a fault. Hover any cell and it tells you the total and how many days went into it.

Efficiency Score

A ring showing focus ÷ span for today: focus is your tracked time, span runs from your first session's start to your last session's end. Breaks in between lower the score. It measures continuity, not the quality of your work.

Recent Activity

Drill down through your history: day → hour → individual blocks, with breadcrumbs. Inside a day, a By hour / All blocks toggle switches between the hours to drill into and every block in the day listed flat. On any list of blocks you can rename, tag or delete a block.

Ticking a block's checkbox opens a bar above the list that acts on the whole selection: Tag applies one tag to all of them, Rename gives them all the same name (leave the box empty to clear their names instead), and Merge fuses two or more into one — use "All blocks" when the blocks you want to merge fall in different hours. The same bar appears under Today's Sessions on the Timer page.

Deski's Recent Activity list with four time blocks selected and a toolbar offering Deselect all, Clear, Tag, Rename and Merge
Selecting blocks in Recent Activity: tag, rename or merge the whole selection at once.

Settings reference

Settings opens on a list of six sections. Tap one to open it; the arrow at the top left returns to the list. Reopening Settings lands on the section you were last in. Paths below are written section → group.

SectionSettingWhat it does
Tracking → TrackMouseTrack mouse activity (clicks + movement). Default on.
KeyboardCount key presses (never which keys). Default off.
Tracking → TimingAuto block idle gapHow long a lull must last before it stops counting as tracked time — 10 seconds to 5 minutes. Default 30 seconds.
Full block lengthHow much tracked time a block holds before it completes and the next one starts — 1 to 60 minutes. Default 10 minutes. Shown as the timer's progress bar.
Pause buttonShow a pause control on the timer. Pausing keeps the block open and leaves the break out of its duration. Default off.
Start/stop button in AutoShow the start/stop button in Auto mode (always shown in Manual). Default off.
Manual trackingShow or hide the Auto/Manual switch. Off = Auto only. Default off.
Appearance → ThemeTheme + Mode8 theme families, each in light and dark.
Appearance → WeekStart of weekWhich day the weekday charts start on.
Appearance → DateDate formatPresets or a custom pattern with live preview (tokens: D, DD, M, MM, MMM, MMMM, YY, YYYY, ddd, dddd).
Appearance → SidebarAuto-hideCollapse the icon rail until you hover it.
Startup → Startup & trayLaunch at startupStart Deski when you sign in to your computer.
Minimize to trayKeep Deski in the system tray instead of the taskbar when minimized.
Startup → SchedulingStart tracking on startupBegin tracking as soon as Deski opens, on the selected days. Default off.
Scheduled hoursStart and stop tracking at a set From/To time on the selected days. Default off; when on, the default window is 09:00–17:00. Once the window closes, the timer says so — a line under the clock reads Outside your scheduled hours and clears as soon as tracking resumes.
DaysWhich days both settings above apply to. On an unselected day Deski does not track on its own even in Auto mode — start it by hand (start/stop button, or Manual) if you need to. An overnight window belongs to the day it starts on.
TagsTag libraryCreate, colour and delete tags — up to 100, names up to 30 characters. Click a tag to recolour it; the picker below applies to that tag until you click away. Only the colour is editable — a tag's name is part of what a timesheet's tamper check commits to. The ten most recent are listed with the rest behind the search box, and tags are creatable straight from a block's + Tag menu.
Default name & tagA block name and tag for work you do day after day. They pre-fill: an unnamed block opens the rename box already filled in, and your default tag is offered first. Nothing is written until you confirm it.
Apply them automaticallyNames and tags every new block the moment it is saved, with no confirmation. Default off on purpose — a block labelled this way carries a claim you didn't look at, and because a timesheet's fingerprint is calculated partly from tags, an automatic tag is part of what the report attests to.
Saved coloursPin up to 10 colours you reuse. + saves the colour you're editing, a filled slot applies it, × clears it.
DataBack upWrite your whole history to a single SQLite file you choose. See Backup, restore & reports.
RestoreReplace everything in the app with the contents of a backup, after a confirmation.
Add a past entryRecord hours you worked but didn't time — a session you forgot to start. Listed on a timesheet as untracked. See Backup, restore & reports.
Timesheet reportPrintable timesheet for a date range, with optional signature lines.
Tamper recordWhether your time blocks have been changed outside Deski, and how to put it right if they have.
Account → AccountSign out / Cancel subscription (with optional data deletion)Manage your sign-in and subscription. Status shows in the app footer.
Account → AboutVersion & updateShows your version. Deski checks for a newer release on its own; when one exists a Download button appears here.
Account → TutorialApp walkthroughReplay the 5-step guided tour.

Data & privacy

Deski is built so that tracking never becomes surveillance:

The only things that touch the network are sign-in and the once-a-day subscription check. Details in the Privacy Policy.

Backup, restore & reports

Everything Deski records stays on your machine, so Settings → Data is how it gets out of the app — for safekeeping, for moving to another computer, or for a client.

Back up

Writes your entire history to a single file you choose (a .db file). It's an ordinary SQLite database, not a Deski-only format, so any SQLite tool — DB Browser for SQLite, TablePlus, the sqlite3 command line — can open it and read your blocks and tags directly. See Query your data with SQL for the tables and some queries to start from.

⚠️ The backup isn't encrypted. Anyone who can open the file can read your tracked time, so treat it as carefully as the app's own data. A tool that offers to decrypt it (TablePlus does) will ask for a password — there isn't one; set the connection's encryption to None.

The Backup row in Deski's Data settings, with Save backup and Restore buttons
Settings → Data → Backup.

Restore

Replaces everything currently in Deski with the contents of a backup, after a confirmation. Deski verifies the file is a genuine Deski backup first and refuses anything else, so picking the wrong file leaves your data untouched. A successful restore can't be undone — back up first if the current data still matters.

Timesheet report

Pick a date range and Deski renders a printable sheet: total hours, a breakdown by tag and by day, and every block listed. Optionally add a Prepared for name and signature lines for client sign-off. Print opens the system print dialog; choose Microsoft Print to PDF (Windows) or Save as PDF (macOS) for a file rather than paper.

A block carrying several tags counts in full under each of them, so a tag's hours always reconcile against that tag's own work. The tag rows can therefore add up to more than the total — bill from the total.

Fill in Rate / hour and Currency and the By day table gains an Amount column, with a grand total at the bottom. Currency is a plain text box — $, USD, , kr, whatever you invoice in. Every figure adds up to every other one: both totals — hours and amount — are the sum of the day rows above them, so whoever adds up a column gets exactly the total shown. Both fields can be remembered for next time (see below); leave the rate blank and no money appears at all.

The printed sheet carries its own header — Generated 2026-08-03 16:56 on the left, Deski on the right — and no browser furniture. The stamp is year-month-day on a 24-hour clock, matching the dates in the tables, because 03/08/2026 reads as 3 August to one person and 8 March to another. Deski prints with a zero page margin and supplies the margin itself, which leaves the browser nowhere to draw its own header and footer, so no timestamp, page number or localhost address lands on a sheet going to a client. (Changing Margins in the print dialog away from Default overrides this and brings the browser header back.)

Cap billable hours. If you work to a retainer or a contract ceiling, tick this and enter Max hours / week. The report gains a By week table — worked, billable, amount — and the grand total is priced on the billable figure. Each week is capped on its own, so forty hours one week and ten the next against a thirty-hour cap bills 30 + 10, not fifty capped once. Weeks follow your start-of-week setting. Hours above the cap are still printed, with a line saying how many weren't billed. With a cap on, the money moves out of the By day Amount column into the By week one: a cap applies to a whole week, and there's no honest way to pick which day inside it loses the hours.

Add signature lines puts a Prepared by and an Approved by rule at the foot of the sheet. Tick Prefill my name and today's date underneath and your own line comes out already carrying both, leaving only the signature to add by hand — the date is the sheet's generated date, so it always matches the header. The Approved by line is left blank on purpose; that one is for whoever signs the work off.

Prepared by defaults to the email you signed in with — type a name to print that instead. Ticking Remember details keeps Prepared for, Prepared by, Rate / hour, Currency and your signature-line settings for next time, so a client you bill several times a month is typed once, your rate is never retyped, and the sheet keeps the shape you set it to. It's off by default, and unticking it erases what was stored.

The tamper-check badge

Deski keeps a running record of every time block as it writes it, each entry sealed against the one before. When you print a timesheet it re-checks every block in the range against that record and prints one of three results at the top of the sheet:

What the badge claims, exactly. A green tick means the blocks in that range have not been casually edited since Deski started recording — someone opening the database in a spreadsheet tool and changing a number gets caught. It does not mean the hours were worked, and it cannot: no software running on your own machine can prove that to somebody else. Anything already in the file when you upgraded is taken as genuine, because the record has to start somewhere. Deski's own Back up and Restore move the blocks and the record together, so restoring a backup verifies clean.

The head of a Deski timesheet showing a red badge reading "Changed outside Deski — 2 blocks", and a summary line reading 25.43 hours tracked across 43 blocks plus 4.00 hours Deski could not verify
A flagged sheet says so at the top, and the summary line names the hours it could not verify rather than folding them into the total.

Two totals, and why a flagged sheet is still sendable

When something is flagged, the sheet stops having a single total. Hours that passed the check are totalled as verified and invoiced; hours that failed are listed underneath with the reason, and are deliberately not added to that total.

This is the part worth knowing before you need it: you are not blocked from billing, and you do not have to fix anything first. Send it. The client pays the total that is certain and can ask about the rest, which is a conversation rather than an accusation. A sheet that quietly dropped the disputed hours, or quietly included them, would be worse for both of you.

Where a sheet's hours came from

Every timesheet breaks its hours into three kinds, so whoever reads it can weigh them:

Deski's Add a past entry dialog with date, from and to fields, an optional description, tag chips and a live duration readout reading That's 8h 0m
Add a past entry — the hours it creates are billable, and the timesheet lists them as untracked.

If a report is flagged

Settings → Data → Tamper record shows what failed and what each fix costs before you choose. It asks one question first — are the flagged hours real work you need to keep? — because that is what decides the answer.

Almost everything flagged at once usually means the database file itself was damaged or rebuilt — by disk trouble, a repair tool, or a sync service reconciling two copies — rather than anyone editing blocks one by one. Restore is the answer there; deleting is not.

The Tamper record row in Deski's Data settings, with a Check and fix button
Settings → Data → Tamper record.
Deski's Check and fix dialog: a heading reading 3 blocks failed the check, the question Are those hours real work you need to keep, and three options - restore, confirm the blocks deleted outside Deski, and delete them
Every option states its cost before you pick it. Restore is recommended; deleting is never the default.

Query your data with SQL

Deski stores everything in a plain SQLite database, so you're never limited to the views the app happens to offer. If you want billable hours per client per month, or your quietest hour of the day, you can just ask.

Open a backup, not the live file

Take a backup first (Settings → Data → Back up) and point your SQL client at that. Two reasons, and both matter:

Treat the backup as read-only. Editing it and restoring it is not a supported way to change your data.

Connecting with TablePlus

  1. Create a new connection and choose SQLite.
  2. For Database file, pick the .db backup you just saved.
  3. Set Encryption to None. TablePlus offers to decrypt SQLCipher databases and will ask for a password — Deski's file isn't encrypted, so there isn't one.
  4. Connect, then open a SQL tab and query away.

Anything that speaks SQLite works the same way — DB Browser for SQLite is free and cross-platform, and the sqlite3 command line is already on macOS and most Linux systems.

⚠️ The backup isn't encrypted, so anyone who can open the file can read your tracked time. Keep it somewhere you'd be comfortable keeping a timesheet.

The tables

TableWhat's in it
time_blocksOne row per tracked session — this is the table you want. start_ts, end_ts, duration_secs (active time, idle already removed), idle_secs, mode (auto or manual), name, note, the click_count / move_count / key_count activity tallies, and entered (1 for hours you added by hand rather than timed).
tagsYour tags: id, name, color.
block_tagsWhich tags are on which block (block_id, tag_id). A block can carry several.
mouse_eventsRaw activity: ts and kind (click or move). No screen coordinates — there is no x or y column to query.
key_eventsRaw key presses: ts only. No key column — Deski records that a key was pressed, never which one.
block_eventsThe tamper record: one append-only row per change Deski makes to a block, each sealed against the one before. This is what the badge on a timesheet is checked against. Read it, don't write it — editing or deleting rows here is itself what the check is looking for, and will flag your own reports.
categories, metaInternal bookkeeping. Leave them alone.

Timestamps are in milliseconds, not seconds — the usual first stumble. Divide by 1000 before handing one to a date function: datetime(start_ts/1000, 'unixepoch', 'localtime').

duration_secs is active time with idle already subtracted, so it's the number to bill from. Summing end_ts - start_ts instead gives you wall-clock, which is a different (larger) figure.

Queries to start from

Hours per day, newest first:

SELECT date(start_ts/1000, 'unixepoch', 'localtime') AS day,
       ROUND(SUM(duration_secs)/3600.0, 2)           AS hours
FROM time_blocks
GROUP BY day
ORDER BY day DESC;

Hours per tag:

SELECT t.name,
       ROUND(SUM(b.duration_secs)/3600.0, 2) AS hours
FROM time_blocks b
JOIN block_tags bt ON bt.block_id = b.id
JOIN tags t        ON t.id        = bt.tag_id
GROUP BY t.name
ORDER BY hours DESC;

As in the timesheet report, a block with several tags counts in full under each, so these rows can add up to more than your actual total. Bill from the total, not the sum of the tags.

One client, one month, with the tags on each block:

SELECT datetime(b.start_ts/1000, 'unixepoch', 'localtime') AS started,
       ROUND(b.duration_secs/3600.0, 2)                    AS hours,
       b.name,
       GROUP_CONCAT(t.name, ', ')                          AS tags
FROM time_blocks b
LEFT JOIN block_tags bt ON bt.block_id = b.id
LEFT JOIN tags t        ON t.id        = bt.tag_id
WHERE b.start_ts >= strftime('%s', '2026-08-01') * 1000
  AND b.start_ts <  strftime('%s', '2026-09-01') * 1000
GROUP BY b.id
ORDER BY b.start_ts;

Which hour of the day you actually work:

SELECT strftime('%H', start_ts/1000, 'unixepoch', 'localtime') AS hour,
       ROUND(SUM(duration_secs)/3600.0, 2)                     AS hours
FROM time_blocks
GROUP BY hour
ORDER BY hour;

Clearing data

⚠️ Deletions cannot be undone. Deski keeps your data local with no cloud backup, so cleared data can't be recovered — it's securely wiped from disk. If you might want it later, take a backup first; restoring one is the only way back.

Updates

When a newer version exists, a small pill appears in the app footer with a download link. A Download button also appears in Settings → Account → About whenever a newer version is available. Updates are installed by running the new installer — your data is untouched.

Troubleshooting

No block appeared in Auto mode

A block opens only once activity is detected. If you were idle, no block is created. Check that mouse and/or keyboard tracking is enabled in Settings → Tracking → Track.

The sign-in code never arrived

Check spam, and that the address is typed correctly. Codes expire after 15 minutes — request a fresh one from the sign-in screen.

"No active subscription" after I subscribed

Click "I've subscribed — check again" on that screen — it re-checks immediately. Make sure you signed in with the same email you used at checkout.

I was signed out unexpectedly

You may have signed in on more than 3 devices — the oldest session is signed out automatically. Just sign in again.

SmartScreen blocks the installer

Expected while builds are unsigned: click More info → Run anyway.

Support

Questions, bugs, ideas — email support@deski-app.com.