doing.el is a direct reimplementation of Brett Terpstra’s excellent doing CLI tool for the Emacs environment. The workflow philosophy, command naming, and core concepts come directly from that project, adapted to work natively with Org-mode.
This package was developed entirely through AI-assisted “vibe coding” using Claude Code and ChatGPT. The overwhelming majority of the code was written by coding agents, with human guidance on design and workflow.
This is an experiment in whether an experienced software engineer can effectively build quality software in an unfamiliar language by leveraging AI coding assistants. The author has limited Emacs Lisp skills (can read basic elisp and copy-paste config snippets), but brings experience across multiple programming languages and technology stacks.
NOTE: I do use the package myself, and I built it because I needed it to exist, the experiment is not the main point here, and I do carefully read what the agents are doing. So, don’t dismiss it because the code is not “free range”. I did put a lot of effort and will continue working on it. It’s just not necessarily in the form of coding.
More detailed reflections on this development approach and the experiment’s outcomes will be published in the future.
doing.el is an Emacs package for frictionless activity logging and time tracking.
It’s designed to answer the question: “What was I doing?”
Unlike traditional task managers that focus on planning future work, doing.el is optimized for capturing what you’re doing right now and generating retrospective reports about where your time went.
- Fast, low-friction capture — Start logging an activity with one command
- Inline @tag syntax — Add tags naturally within your activity description
- Automatic time tracking — Durations computed from timestamps, no manual timers
- Retrospective reporting — View today, this week, or totals by tag
- Project-aware auto-tagging — Automatically tag entries based on current directory
- Org-native storage — All data stored as plain Org-mode files
- Automatic archival — Entries automatically migrate from hot (today.org) to warm (week.org) to cold (archive/) storage
Install directly from GitHub using use-package with :vc:
(use-package doing
:vc (:url "https://github.com/xiaoxinghu/doing.el" :rev :newest)
:bind ("C-c d" . doing-command-map))Note: The :vc keyword requires Emacs 29 or later. For older versions, use manual installation below.
- Clone this repository:
git clone https://github.com/yourusername/doing.el.git - Add to your Emacs configuration:
(add-to-list 'load-path "/path/to/doing.el") (require 'doing)
- Optionally set up keybindings:
(global-set-key (kbd "C-c d") doing-command-map)
- Start an activity:
M-x doing-now RET Write README - Check what you’re doing:
M-x doing-current # => [0:15] Write README * - Finish the activity:
M-x doing-finish # => Finished: Write README (0:23) - View your day:
M-x doing-view-today - Add tags with @tag syntax:
M-x doing-now RET Fix bug @testing @emacs # Tags are extracted automatically
That’s it! No project setup, no file management, just start logging.
When you start a new activity with doing-now, any unfinished activity is automatically finished. This creates a natural flow:
M-x doing-now RET Write tests
M-x doing-now RET Review pull requests # automatically finishes "Write tests"
| Command | Keybinding | Description |
|---|---|---|
doing-now | C-c d n | Start a new activity |
doing-finish | C-c d f | Finish current activity |
doing-cancel | (none) | Cancel current activity (delete) |
doing-again | C-c d a | Resume last finished activity |
doing-note | (none) | Add a note to current activity |
| Command | Keybinding | Description |
|---|---|---|
doing-view-today | C-c d t | Show today’s activities |
doing-view-yesterday | (none) | Show yesterday’s activities |
doing-view-week | C-c d w | Show this week’s activities |
doing-view-recent | (none) | Show N most recent entries |
doing-view-since | (none) | Show entries since a date |
| Command | Keybinding | Description |
|---|---|---|
doing-totals | C-c d T | Show time totals by tag |
doing-search | C-c d s | Search entries by text or @tag |
| Command | Keybinding | Description |
|---|---|---|
doing-current | C-c d c | Show current activity in minibuffer |
doing-last | (none) | Show last entry |
doing-edit | C-c d e | Open today.org and jump to current |
doing-open | C-c d o | Open a doing log file |
Add tags when starting an activity to enable filtering and reporting.
The easiest way to add tags is using inline @tag syntax:
M-x doing-now RET Fix authentication bug @backend @bug
The @tags are automatically extracted and removed from the title. The entry is saved as:
* Fix authentication bug :backend:bug:
You can use @tags anywhere in the title:
M-x doing-now RET Writing @documentation for the API
# => Creates: "* Writing for the API :documentation:"
When calling doing-now programmatically, you can also provide tags as a list:
(doing-now "Fix authentication bug" '("backend" "bug"))Inline @tags and programmatic tags are merged together if both are provided.
Configure automatic tags based on your current directory:
(setq doing-auto-tags
'(("~/projects/doing.el" :project "doing-el" :tags ("emacs" "elisp"))
("~/projects/api" :project "api" :tags ("backend" "go"))
("~/projects/website" :project "website" :tags ("frontend" "react"))))Now when you call doing-now from within these directories, tags and project properties are applied automatically.
Auto-tags are merged with inline @tags and programmatic tags, with user-provided tags taking precedence:
# From ~/projects/doing.el directory:
M-x doing-now RET Fix bug @testing
# => Creates: "* Fix bug :testing:emacs:elisp:"
# (inline @testing + auto-tags emacs, elisp)
Add context to your current activity:
M-x doing-note RET Found the issue in session middleware
M-x doing-note RET Updated auth flow diagram
Notes are appended to the entry body and preserved during archival.
See where your time went this week:
M-x doing-totals
Totals for 2026-W04
By tag:
emacs 4:30
backend 3:15
frontend 2:45
bug 1:30
----------------
Total 12:00
Search by text:
M-x doing-search RET authentication
Search by tag:
M-x doing-search RET @bug
Quickly resume your last activity:
M-x doing-again
# Creates a new entry with the same title and tags as your last finished activity
doing.el uses a three-tier storage system optimized for performance:
~/org/doing/
├── today.org # Hot: today's activities only
├── week.org # Warm: current ISO week
└── archive/
├── 2026-W01.org # Cold: archived weeks
├── 2026-W02.org
└── 2026-W03.org
Entries automatically migrate between files:
- Daily: At midnight, yesterday’s entries move from
today.orgtoweek.org - Weekly: On Monday, last week’s entries move from
week.orgtoarchive/YYYY-WNN.org
Rollover happens lazily (triggered by commands) and is throttled to once per hour for performance.
Each activity is stored as an Org headline with tags:
* Write README :emacs:documentation:
:PROPERTIES:
:ID: 20260124T153000
:STARTED: [2026-01-24 Fri 15:30]
:ENDED: [2026-01-24 Fri 16:15]
:DURATION: 0:45
:PROJECT: doing-el
:END:
Added installation instructions and usage examples.
Tags can be added using inline @tag syntax when creating the entry:
M-x doing-now RET Write README @emacs @documentation
;; Optional: change the storage directory (default: ~/org/doing/)
(setq doing-directory "~/Documents/doing/")
;; Optional: set up keybindings
(global-set-key (kbd "C-c d") doing-command-map)(setq doing-auto-tags
'(("~/work/project-a" :project "project-a" :tags ("work" "client"))
("~/personal" :project "personal" :tags ("personal"))))Alternatively, use .dir-locals.el for per-project configuration:
((nil . ((doing-project . "my-project")
(doing-default-tags . ("tag1" "tag2")))))doing.el is designed around a few core principles:
The barrier to logging an activity should be as low as possible. You don’t need to think about projects, categories, or file structure—just describe what you’re doing and start.
Traditional task managers focus on planning what you’ll do. doing.el focuses on recording what you did. This makes it perfect for:
- Timesheet generation
- Billing and invoicing
- Retrospective analysis
- Understanding work patterns
Common operations (doing-now, doing-finish) require minimal input. Timestamps, durations, and IDs are all generated automatically.
All data is stored as standard Org-mode files. You can:
- Edit entries manually in Org-mode
- Use Org-mode features (links, formatting, etc.)
- Export using Org’s export system
- Process files with any Org-aware tool
- Emacs: 27.1 or later
- Org-mode: 9.0 or later (built-in with Emacs)
Running Tests.
make test # Run all tests
make compile # Byte-compile package
make clean # Remove compiled filesMIT License
Xiaoxing Hu — hi@xiaoxing.dev
