Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

X TIME

A Chrome extension that counts the time you actually spend on X — not the time the tab sat open — and gets loud when you blow through your daily budget.

Clinical instrument UI: paper #eceff3, ink #0e1116, one blue #1b34d8, and red #d80027 reserved for exactly one thing — the time you took past the budget. Nothing decorative is red. Instrument Sans and Roboto Mono, bundled, no webfont request. No rounded corners, no gradients, nothing that blinks.


Install

Not on the Chrome Web Store. Four steps:

  1. Grab xtime-<version>.zip from Releases and unzip it.
  2. Open chrome://extensions.
  3. Turn on Developer mode (top right).
  4. Load unpacked → pick the unzipped folder.

Leave that folder where it is. Chrome loads the extension from the path you picked — move it or delete it and the extension goes with it. Put it somewhere you won't tidy up, not in Downloads.

Two things to know: Chrome will occasionally nag about developer-mode extensions on startup, and there are no auto-updates — new version means downloading it again and hitting the refresh icon on the card.

Set your daily limit in the popup. It defaults to 30 minutes.


What "actually" means

The clock only advances when all of these are true:

Signal Check
Tab is the one you're looking at document.visibilityState === "visible"
The window has OS focus document.hasFocus()
You've touched something recently pointer / key / scroll / touch within the idle grace (default 45s)

The grace window is the important part. It's long enough to read a thread without your hands moving, short enough to stop the clock when you walk away.

Two deliberate exceptions:

  • Video you chose to watch counts even with your hands off — but only if it's unmuted and on screen. Muted autoplay in the feed is the timeline playing at you, not you watching it, so it doesn't count.
  • A single reported chunk is capped at 30s. Sleep the laptop mid-session and it can't donate three hours to today's total on wake.

Only one tab can satisfy focus + visibility at a time, so two X tabs never double-count. Writes are serialised in the service worker regardless.

The roast

Cross your limit and X is taken over by a full-screen card. It escalates:

At Tier
TIME'S UP
1.5× STILL HERE
DOUBLE. YOUR. LIMIT.
ENOUGH.

Each tier fires once. Past 3× it comes back every 15 more active minutes. Buttons are dead for 4 seconds so you have to actually read it. Then there are exactly two doors: close the tab, or earn 5 more minutes.

Copy lives in src/roasts.js. Add lines there; nothing else needs to change.

Earning 5 minutes

Not a button — a gate. It pulls a fresh article on AI / agentic dev, makes you read it, then makes you write back what it said.

No backend, no model, no API key. The extension fetches a public RSS feed directly and does the rest with string work.

  1. Read it. Scroll to 85% and dwell for a length-scaled minimum (45s floor, 2.5 min ceiling). The dwell clock only runs while the window is focused.
  2. Write it back. 50 words minimum, typed. Paste is off.

How the check works

It checks two things: that you wrote 50 words, and that you wrote them yourself. That is all.

It does not grade whether your recall is about the article. An earlier version did — scoring your answer against the article's distinctive terms by document frequency — and it kept rejecting honest recalls that happened to describe the piece in different nouns than the piece used. Being told you weren't paying attention when you were is worse than the cheat it prevented. The gate was never meant to mark you correct. It's meant to make you read something and put it into your own words before you get back on the timeline.

So the clipboard is the only thing left to defend against, and it's defended twice:

  • The textarea refuses paste and drop outright, and reverts any single edit that drops more than 24 characters in at once. Undo and redo still work.
  • The service worker re-checks by coverage, for anything that got around the page — devtools, another extension. More than 40% of your words sitting inside a 6-word run lifted verbatim from the article is a paste. One incidental overlap is fine: "the app that used to be called Codex" is simply how anyone would recall that sentence.

Measured against real articles (test/reading.test.mjs): three genuine ~60-word recalls land at 0%, 0% and 11.7% coverage; every pasted paragraph lands at 100%.

This is a commitment device, not a security system — you are both the lock and the lockpick. The point is to cost more than the impulse is worth.

Sources

Seven feeds, all carrying full article text inline — no page scraping needed:

Source Focus
Simon Willison Daily, practical, filtered to AI tags
Interconnects Post-training, RL, model releases
Latent Space AI engineering essays
Import AI Weekly research roundup
Hamel Husain Evals and LLM practice
Chip Huyen AI engineering
Sebastian Raschka Deep LLM tutorials

Across all seven, ~59 articles are readable at any time. A pasted paragraph is rejected on all 59.

Summary-only feeds are useless here — there is nothing to recall — which rules out OpenAI news, the Google AI blog, Hugging Face and Eugene Yan. Anthropic publishes no RSS at all (every standard path 404s, and their engineering page advertises none), though Simon's AI tag tracks their releases closely.

Each feed is a named host in the manifest; there is no <all_urls>. Three articles are kept warm in the background so the gate never stalls, and you won't see the same piece twice in 40.

If no feed is reachable you get an offline card: close the tab, retry, or dismiss — dismissing grants no silence, so the roast returns.

Install

  1. chrome://extensions → enable Developer mode
  2. Load unpacked → select this folder
  3. Pin it. The toolbar badge shows today's minutes — wheat under the limit, terracotta over, red at 2×.

Tuning

Click the badge → SET.

  • Daily limit — default 30 min. That's active time, which is a lot more scrolling than it sounds.
  • Idle grace — default 45s.
  • Let the roast close the tab — on by default.
  • Reset today — two taps, in case something counted that shouldn't have.

Layout

manifest.json      MV3. storage + alarms + notifications, x.com/twitter.com only.
src/background.js  Accounting, day rollover, tier logic, badge, notifications.
src/content.js     Attention detection + the roast overlay (closed shadow DOM).
src/roasts.js      Copy bank, shared by the worker and the popup.
src/reading.js     Feed fetch, parse, distinctive-term scoring. No DOM, no model.
popup/             The dashboard.
assets/            Icons + the bundled Outfit face (no remote font fetch).
test/              Headless logic tests.
dev/               Browser previews + the icon generator. Not shipped code.

No analytics and no telemetry. The only network requests are GETs to the seven feeds above; nothing about you is ever sent anywhere. History is kept for 60 days and pruned.

Development

node test/logic.test.mjs        # 37 assertions over the accounting + roast logic
node test/reading.test.mjs      # 32 over feed parsing + the recall gate (offline fixture)
node test/reading.test.mjs --live   # ...plus one real fetch
python3 -m http.server 8931     # then open:
#   /dev/preview.html?state=over|under|crit[&prefs=1]   popup, canned data
#   /dev/preview-roast.html[?fast=1][&visible=1]        roast + reading gate, real content script
python3 dev/make-icons.py       # regenerate icons from the X mark

About

Counts the time you actually spend on X. Read an article to get more time on X.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages