wenjoy26 downloadsRun 25-minute tomato timers and log tasks, interruptions, and statistics to Markdown.
A Pomodoro-style tomato timer for Obsidian that keeps a plain-Markdown log of every session, so your focus time, interruptions, and task history stay in your vault instead of a separate app.
Start a 25-minute tomato, get interrupted, log what pulled you away, and watch the day's totals and long-term trends build up — all from a side panel, all stored as text you can read, edit, and search.
isDesktopOnly: false).main.js, manifest.json, and styles.css from the latest release.<your-vault>/.obsidian/plugins/tomato-countdown/.wenjoy/tomato-log-obisidian-plugin.write release notes) and press Start.When the countdown hits zero, the tomato is logged automatically, a system notification fires, and the panel returns to idle.
Interruptions are cheap to log: press Cmd/Ctrl + Enter in the interruption dialog, or Enter in the abandon reason field.
| Action | What happens |
|---|---|
| Interrupt | Records a distraction with a reason. The clock keeps running; the tomato's quality drops as interruptions accumulate. |
| Abandon | Stops the clock, asks for a reason, and logs the session as 🤢 (rotten), including the partial focus time. |
| Cancel an abandon prompt | The clock stays stopped (Stopped, or Interrupted (n) if you already logged distractions). Start becomes Resume, which continues from the remaining time. |
Tomato quality is derived from the interruption count at completion: 0 → 🙂, 1 → 🙁, 2+ → 🤢. Abandoned tomatoes are always 🤢.
Every record is written to the log file configured in settings (default: Tomato Timer Log.md at the vault root). The file is organised by date; a new day's section is created at the top, and each new record is inserted right below its date heading, so the newest record is always first.
# 2026-07-08
#### [13:40-14:05] (🙂🍅, 25m)-write release notes-3
#### [11:02-11:09] (🤢🍅, 7m)-refactor log parser-2
- abandoned: client meeting moved up
#### [09:15-09:40] (🤢🍅, 25m)-refactor log parser-1
- Slack notification
- Email
Each record is a level-4 heading, optionally followed by bullet lines:
#### [<start>-<end>] (<quality>🍅, <minutes>m)-<task name>-<count>
<start>-<end> — local wall-clock time of the session.<quality> — the tomato rating described above.<minutes> — minutes actually spent focusing (a completed tomato logs the full duration; an abandoned one logs the elapsed portion, minimum 1 minute).<task name> — the normalised task you typed.<count> — which tomato this is for that task across the whole log (a running counter, stripped when statistics are computed).Bullet lines under the heading are the interruptions (and an abandoned: <reason> line for abandoned sessions). A clean tomato has no bullets.
Because the log is plain text, you can edit, reorder, or delete entries; statistics re-read the file on every refresh. Older heading variants written by previous versions — including the form that stored the interruption count inline — are still parsed. Refreshing statistics also removes leftover inline statistics blocks and State buttons written by earlier builds.
Open it with the Statistics button in the timer panel or Tomato Countdown: Open statistics. The view reads the log file and supports four tabs:
| Tab | What you see |
|---|---|
| Day | A year contribution grid (one cell per day across the 12 months of the year your latest entry falls in, shaded by tomato count: 0, 1–3, 4–6, 7–9, 10+) plus the selected day's metrics, quality breakdown, and per-task table. |
| Week | Vertical bars per week, with the same metrics and breakdowns for the selected week. |
| Month | Vertical bars per month, with the same metrics and breakdowns for the selected month. |
| Task | Overall totals plus one row per task: tomatoes, good / bad / rotten counts, and interruptions. |
Metrics shown for the selected period: tomatoes, interruptions, completed, and abandoned. Click any bar or heatmap cell to switch the period; Refresh re-reads the log.
| Setting | Default | Description |
|---|---|---|
| Countdown duration | 25 |
Length of a tomato in minutes (minimum 1). |
| Log file path | Tomato Timer Log.md |
Vault-relative path of the log file. Created automatically on the first record. |
| Clear task history | — | Removes the saved task-name suggestions. |
| Command | ID | Notes |
|---|---|---|
| Open timer | open |
Opens or reveals the timer panel. |
| Start timer | start |
Opens the task dialog, then starts and reveals the panel. |
| Interrupt timer | interrupt |
Only available while a countdown is running. |
| Abandon timer | abandon |
Only available while a countdown is running or paused. |
| Open statistics | open-statistics |
Opens or reveals the statistics view. |
Completion and abandonment trigger a system notification through the Web Notifications API, once Obsidian has been granted permission. Completed tomatoes also show a 10-second in-app notice. Logging an interruption does not notify, since the timer keeps running.
System notifications are best-effort: they work in the desktop app, while some mobile builds don't expose the Notification API at all. The in-app notice always works, and the plugin never uses Node.js or Electron APIs, so it installs and runs on mobile.
data.json inside the plugin folder.npm install # install dependencies
npm run dev # watch mode: rebuilds main.js on change
npm run build # type-check, then produce a minified production bundle
npm run lint # lint against the Obsidian plugin guidelines
Source layout:
| Path | Purpose |
|---|---|
main.ts |
Plugin entry point: timer state, log writer/parser, views, modals, settings tab. |
styles.css |
Styling for the timer panel and statistics view. |
main.js |
Generated bundle (gitignored); produce it with npm run build. |
manifest.json |
Plugin metadata and minimum Obsidian version. |
versions.json |
Version → minimum Obsidian version map. |
To test locally, copy main.js, manifest.json, and styles.css into <vault>/.obsidian/plugins/tomato-countdown/ and reload the plugin.
Releases are automated: pushing a tag that matches the version in manifest.json runs .github/workflows/release.yml, builds the plugin, and attaches main.js, manifest.json, and styles.css to a GitHub release.
Requires Obsidian 1.7.2 or newer.
Version history and notable changes live in CHANGELOG.md.
Released under the MIT License. © 2026 wenjoy