This is not a feature list. This is one person’s real daily workflow with Supertag, documented in the style of Bernt Hansen’s legendary org-mode tutorial.
Every section shows:
- What I actually do
- The exact commands and Elisp I use
- Why I chose this way over alternatives
You can load this file in Emacs and tangle it with C-c C-v C-t to extract all the
Elisp examples into supertag-workflow.el, then include it in your init.el.
This document assumes you have Supertag installed. See the README for installation.
中文版:Supertag 的一天(中文)
I keep my life in a handful of Org files under ~/org/. Each file has a clear purpose,
and Supertag treats them all as one unified knowledge base.
| File | Purpose |
|---|---|
inbox.org | Capture bucket — everything lands here first |
projects.org | Active projects, each a level-1 heading |
research.org | Papers, reading notes, literature reviews |
meetings.org | Meeting notes with decisions and actions |
journal.org | Daily journal entries, ideas, reflections |
Why separate files? Because Supertag queries across all of them. The file division
is for my brain — Supertag doesn’t care which file a heading lives in. A #task in
meetings.org and a #task in projects.org appear side by side in the Table View.
I use a single vault for everything. If I wanted work/personal separation, I’d use:
;; Single vault (my setup)
(setq supertag-sync-directories '("~/org/"))
;; Multi-vault alternative — separate DBs for work and personal
;; (setq supertag-sync-directories '("~/org/work/" "~/org/personal/"))
;; (setq supertag-sync-directories-mode 'vaults)I want sync to run automatically but not aggressively. 60-second intervals strike a good balance — I never wait long for new content to appear, and Emacs stays responsive.
;; Auto-sync every 60 seconds
(setq supertag-sync-directories '("~/org/"))
(setq supertag-auto-sync-interval 60)
;; Only do full validation every 10th tick (saves CPU)
(setq supertag-sync-maintenance-every-n-ticks 10)
;; Snapshot guard: if a directory is unavailable (network drive),
;; skip destructive operations instead of treating files as deleted
(setq supertag-sync-snapshot-guard t)I’ve thought carefully about my tags. They form a hierarchy with inheritance — child tags automatically get the parent’s fields.
;; ── Top-level tags ──
;; #project → has fields: status, priority, deadline, owner
;; #task → extends nothing, has fields: status, priority, due, project
;; #paper → has fields: authors, year, venue, status, rating, topic
;; #meeting → has fields: date, participants, decisions, action-items
;; #idea → has fields: status, feasibility, related-project
;; #person → has fields: role, email, notesI define these in the Schema View (M-x supertag-view-schema) — not in code. But here’s
what the data structure looks like under the hood:
;; Example: registering a tag and its fields programmatically
;; (Normally done via Schema View UI — this is just to show the structure)
;; supertag-tag-create creates a tag
;; supertag-schema--add-field-at-point adds a field to a tag in the Schema View
;; #paper fields defined:
;; authors : text
;; year : number
;; venue : text
;; status : select → unread | reading | done
;; rating : number 1–5
;; topic : textWhy inheritance matters: If I later create a #paper/ai tag that extends #paper,
it automatically gets authors, year, status, etc. I only need to add AI-specific
fields like model or dataset.
I start every morning with one command: M-x supertag-view-table, choose tag task.
What I see: a spreadsheet-style view of all #task nodes across all my Org files.
Columns: status, priority, due, project, plus any custom fields I’ve defined.
;; Key bindings I use in Table View:
;; o → jump to the heading in its Org file
;; C-o → jump to referenced node
;; e → edit current cell
;; s → sort by current column
;; / → filter rows
;; TAB → expand/collapse row details
;; ? → help (all keybindings)First thing I do: filter to status ! done=, sort by priority.
;; In the Table View:
;; / → filter → status → != done
;; s → sort → priority (ascending)
;; Equivalent from Elisp:
(supertag-search
'(and (tag "task")
(not (field "status" "done"))))I scan the top 10 items. If anything is overdue (due before today), I either reschedule
it or move it to the top of the list. Editing a cell takes one keystroke.
Sometimes during review I remember things. Instead of switching context, I capture:
;; M-x supertag-capture
;; Choose tag: task
;; Fill fields: title, status=todo, priority=medium
;; → Instantly appears in the tableFifteen minutes, and I know exactly what I’m working on today.
This is the biggest win of Supertag over plain Org-mode. Capture is fast and structured — I don’t need to remember field names or syntax.
I’m deep in coding, a thought pops up: “need to update the API docs.” I don’t switch buffers. I don’t find the right file. I just:
M-x supertag-capture- Select tag
task - Type title: “Update API docs for v2.1”
- Set
priority=high,project=backend C-c C-c→ done. Back to coding. 8 seconds.
The task is in my inbox.org (my configured capture file) with all fields populated.
It appears in the Table View automatically after the next sync cycle.
In a meeting, I open my meetings.org and type:
* Weekly Standup 2025-06-12 #meeting ** Updates - Backend: API v2 deployed, monitoring looks good - Frontend: PR #234 under review - DevOps: CI pipeline speed improved by 30% ** Decisions - Move release date to June 20 - Use PostgreSQL 16 for the new service ** Action Items - @alice: draft release notes - @bob: run load tests on staging
Supertag reads this and:
- Extracts the
#meetingtag - Uses the extractor pipeline to pull
todokeywords,scheduled, etc. - Makes it queryable alongside all other
#meetingnodes
Later, I’ll add structured fields (date, participants, decisions) through the
Node View. But during the meeting, I type naturally.
I’ve set up automation rules so I don’t have to manually populate every field. Here are the rules I rely on:
;; Rule 1: When a #meeting node is created, auto-set the date to today
(supertag-automation-create
'(:name "auto-date-for-meetings"
:trigger :on-node-create
:condition (tag "meeting")
:actions ((update-field "date" (format-time-string "%Y-%m-%d")))))
;; Rule 2: When a #task's status changes to "done", record the completion time
(supertag-automation-create
'(:name "record-done-time"
:trigger :on-field-changed
:condition (and (tag "task")
(property-changed "status"))
:actions ((when (equal (field-value "status") "done")
(update-field "completed-at"
(format-time-string "%Y-%m-%d %H:%M"))))))
;; Rule 3: New #paper auto-sets status to "unread"
(supertag-automation-create
'(:name "new-paper-unread"
:trigger :on-node-create
:condition (tag "paper")
:actions ((update-field "status" "unread"))))How to manage rules:
M-x supertag-view-table→ choose tag →?→A(automations) → see all rules for this tag- Enable/disable rules without deleting them:
supertag-automation-enable/disable - Dry-run a rule to test it: see
doc/AUTOMATION-SYSTEM-GUIDE.md
Why automation matters: I define the logic once, and Supertag applies it every time. No more “oops, forgot to set the date on that meeting note.”
I spend 60% of my Supertag time in the Table View. It behaves like a lightweight database client, but it’s all Emacs.
Things I do regularly:
| Action | How |
|---|---|
| Sort by any column | s → pick column |
| Filter (e.g., status=active) | / → status → = active |
| Bulk edit (mark rows, set field) | m to mark, then B to batch-edit |
| Add a new column | M-x supertag-view-table-add-column |
| Save this view as a named view | M-x supertag-view-table-save-current-view-as-named |
| Switch between named views | M-x supertag-view-table-switch-view |
| Export to Org file | M-x supertag-search-export-results-to-file |
Named views are a game-changer. I have:
today-tasks:#task, filtered tostatus !done=, sorted bypriorityreading-queue:#paper, filtered tostatus = unread, sorted byyeardescactive-projects:#project, filtered tostatus = activerecent-meetings:#meeting, filtered todate >-7d=
;; Named views are stored in supertag--view-configs.
;; They can be saved to file and shared:
(supertag-view-config-save-to-file "~/org/supertag-views.el")
;; On another machine:
(supertag-view-config-load-from-file "~/org/supertag-views.el")For #task and #project, the Table View is great for querying, but the Kanban is
better for doing.
M-x supertag-view-kanban → choose tag task → columns by status
┌──────────┬──────────┬──────────┐ │ TODO │ DOING │ DONE │ ├──────────┼──────────┼──────────┤ │ Fix auth │ Rewrite │ Deploy │ │ bug │ sync │ v2.1 │ │ Update │ layer │ │ │ docs │ │ │ └──────────┴──────────┴──────────┘
I drag tasks between columns as they progress. Supertag updates the status field
automatically. If I have automation rules on status change (like recording completion
time), they fire immediately.
When I need to fill in a single node’s fields in detail, I use the Node View:
M-x supertag-view-node
This opens a side panel showing every field for the current node, with:
- Text fields: type freely
- Select fields: choose from a dropdown
- Number fields: validated input
- Date fields: Org date picker
- Reference fields:
C-oto jump to referenced node
I use this for papers (filling authors, year, venue, abstract) and for meetings
(adding participants, decisions post-meeting).
Some information I want to see but don’t want to store. Virtual columns compute values on the fly.
;; Virtual column: "overdue" — true if due date is in the past and task isn't done
(supertag-virtual-column-register
:name "overdue"
:tag "task"
:compute (lambda (node)
(let ((due (plist-get node :due))
(status (plist-get (supertag-field-value node "task" "status"))))
(and due
(not (equal status "done"))
(time-less-p (date-to-time due) (current-time))))))
;; Virtual column: "progress" — percentage of subtasks done
(supertag-virtual-column-register
:name "progress"
:tag "project"
:compute (lambda (node)
(let* ((subtasks (supertag-get-children node))
(total (length subtasks))
(done (cl-count-if (lambda (s) (equal "done" (plist-get s :status)))
subtasks)))
(if (> total 0) (round (* 100.0 (/ done total))) 0))))Virtual columns appear in the Table View just like regular fields. The difference: they’re computed fresh every time you open the view — zero storage, always up to date.
See doc/VIRTUAL_COLUMNS.md for the full API.
I’m reading a paper and realize it’s directly relevant to a project. Instead of copy-pasting links, I use:
M-x supertag-add-reference
This writes one forward Org link in the current node. The target’s backlink is
derived from that link, so the reference appears in both nodes’ Refs views
without inserting reciprocal text into the target file.
;; The source Org [[link]] owns the reference.
;; Supertag projects it as a queryable :reference relation:
;; 1. The target file is never modified
;; 2. Backlinks are derived by querying relations-to
;; 3. It appears in the Table View Refs column
;; 4. C-o in Table View jumps to the referenced nodeWhen I define a tag hierarchy (#paper/ai extends #paper), I’m creating a schema
relationship. All #paper/ai nodes are also #paper nodes — they inherit fields
and appear in #paper queries.
;; In Schema View (M-x supertag-view-schema):
;; - Navigate to #paper/ai
;; - M-x supertag-view-schema-set-extends → choose #paper
;; - #paper/ai now inherits: authors, year, venue, status, rating, topic
;; - Add AI-specific fields: model, dataset, metricsWhy this matters: I query #paper to see all papers. I query #paper/ai to see
only AI papers. Both queries work because of inheritance.
When I want to see how my notes connect spatially, I open the Board UI:
M-x supertag-board-open
This opens a web-based canvas (React Flow) in my browser. It shows:
- Nodes as cards with title, tags, and fields
- Edges as lines between related nodes, colored by relation type
- Groups as visual containers for organized clusters
Features I use:
- Click a tag on a card → expand to see field values
- Expand card → see full note content with scroll
- Drag nodes into groups for visual organization
- Search bar at top (Ctrl+F) → highlight matching nodes, dim others
- Layout button → auto-arrange nodes with Sugiyama algorithm
- Double-click edge → edit relation label
- Click × on edge → remove relation
The Board UI is best for exploration and sensemaking — when I’m trying to understand how ideas connect, not when I’m filling in data.
At the end of the day, I want to see what I decided today. Structured search makes this trivial:
M-x supertag-search
;; Today's meetings
(supertag-search
'(and (tag "meeting")
(after "-1d")))
;; High-priority tasks still open
(supertag-search
'(and (tag "task")
(field "priority" "high")
(not (field "status" "done"))))
;; Papers I read today (if I updated the status)
(supertag-search
'(and (tag "paper")
(field "status" "done")
(after "-1d")))I can save search results to a file:
M-x supertag-search-export-results-to-file → produces an Org file with all matching
headings and their fields.
Sometimes I don’t know the right query. I just have a question. That’s where the RAG (Retrieval-Augmented Generation) feature shines:
M-x supertag-rag-ask
> What decisions did we make about the API architecture this month? Supertag: - Searches all #meeting nodes from the past month - Finds relevant passages about API architecture - Generates a structured answer with citations - Displays it in a *Supertag RAG Answer* buffer
For this to work, you need an LLM provider configured:
;; Option A: OpenAI
(setq supertag-rag-provider
(llm-make-openai "gpt-4o" :key "sk-..."))
;; Option B: Gemini (free tier available)
(setq supertag-rag-provider
(llm-make-gemini "gemini-2.5-flash" :key "..."))
;; Option C: Ollama (fully local, no API key)
(setq supertag-rag-provider
(llm-make-ollama "llama3.2" :host "localhost:11434"))
;; Option D: Set global default for all llm.el applications
(setq llm-chat-default-provider
(llm-make-openai "gpt-4o" :key "sk-..."))RAG has three modes:
:smart(default): searches notes first, falls back to general AI if nothing found:rag-only: strictly local notes only:general-only: skip search, ask AI directly
Using the View Framework, I’ve built a custom dashboard that shows everything I care about in one buffer:
(supertag-view-define-from-config
(list :id 'evening-review
:name "Evening Review Dashboard"
:tag "task"
:widgets
(list
(list :type :section :title "✅ Tasks"
:children
(list
(list :type :stats-row
:stats
(lambda (context)
(list (cons "Total"
(length (plist-get context :nodes))))))))
(list :type :toolbar
:items '("M-x supertag-view-refresh" "q quit-window")))))
(supertag-view-select-and-render "task")See doc/VIEW_FRAMEWORK_DEV_GUIDE.md for the full View Framework API.
M-x supertag-sync-status shows me:
- When the last sync ran
- How many files are tracked
- How many nodes are in the database
- Whether any sync errors occurred
If anything looks off:
;; Rebuild Org projections from a complete snapshot
M-x supertag-reindex-org
;; This only reads your Org files. Semantic Facts in the database
;; are preserved; restore them from backup if the DB itself was lost.I review my tags in the Schema View (M-x supertag-view-schema) and ask:
- Are there fields I never use? → Remove them
- Are there fields I wish I had? → Add them
- Should any tags be merged or split?
- Is the inheritance hierarchy still right?
Supertag auto-saves snapshots daily (configurable):
(setq supertag-db-auto-save-interval 300) ; auto-save every 5 minutes
(setq supertag-db-backup-interval 86400) ; daily backup
(setq supertag-db-backup-keep-days 3) ; keep 3 days of backupsBackups are stored in ~/.emacs.d/supertag/backups/.
I check whether my automation rules are still doing what I want:
M-x supertag-view-table→ ? → A → see all automations for this tag- Disable rules that are causing noise
- Add rules for new patterns I’ve noticed
This section contains every Elisp setting referenced above, in one place. Tangle this
file with C-c C-v C-t to produce supertag-workflow.el, then:
(load "~/path/to/supertag-workflow.el");;; supertag-workflow.el — My Supertag daily workflow configuration
;; ── Installation ──
;; (straight-use-package '(supertag :host github :repo "yibie/supertag"))
;; ── Sync ──
(setq supertag-sync-directories '("~/org/"))
(setq supertag-auto-sync-interval 60)
(setq supertag-sync-maintenance-every-n-ticks 10)
(setq supertag-sync-snapshot-guard t)
;; ── Persistence ──
(setq supertag-db-auto-save-interval 300)
(setq supertag-db-backup-interval 86400)
(setq supertag-db-backup-keep-days 3)
;; ── RAG (AI Queries) ──
;; Uncomment and configure ONE of these:
;; (setq supertag-rag-provider (llm-make-openai "gpt-4o" :key "sk-..."))
;; (setq supertag-rag-provider (llm-make-gemini "gemini-2.5-flash" :key "..."))
;; (setq supertag-rag-provider (llm-make-ollama "llama3.2" :host "localhost:11434"))
;; ── Automation Rules ──
;; Rule 1: Auto-set meeting date
(supertag-automation-create
'(:name "auto-date-for-meetings"
:trigger :on-node-create
:condition (tag "meeting")
:actions ((update-field "date" (format-time-string "%Y-%m-%d")))))
;; Rule 2: Record task completion time
(supertag-automation-create
'(:name "record-done-time"
:trigger :on-field-changed
:condition (and (tag "task") (property-changed "status"))
:actions ((when (equal (field-value "status") "done")
(update-field "completed-at" (format-time-string "%Y-%m-%d %H:%M"))))))
;; Rule 3: New papers default to unread
(supertag-automation-create
'(:name "new-paper-unread"
:trigger :on-node-create
:condition (tag "paper")
:actions ((update-field "status" "unread"))))
;; ── Virtual Columns ──
(supertag-virtual-column-register
:name "overdue"
:tag "task"
:compute (lambda (node)
(let ((due (plist-get node :due))
(status (plist-get (supertag-field-value node "task" "status"))))
(and due
(not (equal status "done"))
(time-less-p (date-to-time due) (current-time))))))
(provide 'supertag-workflow)
;;; supertag-workflow.el ends hereThis is my most-used commands, not the full list. For the complete reference, see the README.
| Command | I use it for… | Frequency |
|---|---|---|
M-x supertag-view-table | Morning review, paper queue, project overview | Daily |
M-x supertag-capture | Quick task/idea capture without leaving flow | Daily |
M-x supertag-search | Finding things across all files | Daily |
M-x supertag-view-node | Detailed editing of one node’s fields | Weekly |
M-x supertag-view-kanban | Dragging tasks through workflow | Daily |
M-x supertag-view-schema | Adding/removing fields, tag hierarchy | Weekly |
M-x supertag-add-reference | Linking two related ideas | Daily |
M-x supertag-add-tag | Tagging a heading for the first time | Daily |
M-x supertag-rag-ask | “What did I decide about X?” | Weekly |
M-x supertag-board-open | Visual knowledge exploration | Weekly |
M-x supertag-sync-status | Health check | Weekly |
M-x supertag-reindex-org | Rebuild Org projections | Monthly |
M-x supertag-sync-cleanup-database | Fix inconsistencies | As needed |
(global-set-key (kbd "C-c t") 'supertag-view-table)
(global-set-key (kbd "C-c k") 'supertag-view-kanban)
(global-set-key (kbd "C-c c") 'supertag-capture)
(global-set-key (kbd "C-c s") 'supertag-search)
(global-set-key (kbd "C-c r") 'supertag-add-reference)
(global-set-key (kbd "C-c g") 'supertag-add-tag)I document what I stopped using so others don’t waste time:
supertag-sync-directories-mode 'unifiedwith 10+ directories → switched to vault mode. Too slow scanning everything every tick.- Automation rule with
:on-store-changedtrigger → too noisy. Switched to specific triggers (:on-field-changed,:on-node-create). - Manual sync only → missed too many updates. Auto-sync with 60s interval is the sweet spot.
- Trying to define all fields upfront in Schema View → better to add fields as you discover you need them.
- README — Installation and first 5 minutes
- Automation Guide — Full trigger/condition/action reference
- Capture Guide — Capture system deep-dive
- Sync Configuration — Performance tuning, vault mode, troubleshooting
- View Framework — Build custom dashboards
- Virtual Columns — Computed fields API
- Architecture — Internal design (Chinese)
- Plugin Guide — Build your own extractors and services