Unified org-mode CLI: lint, format, query, clock, export. Runs without Emacs.
For almost ten years I maintained a janky toolchain of Python scripts and Emacs Lisp hacks to keep my org files consistent. It worked — mostly — until it didn’t: scripts broke on edge cases, elisp ran only inside Emacs, and nothing could run in CI without pulling in a full Emacs installation.
org-tools replaces all of that with a single Rust binary. It is fast, correct (rules are validated against the org-mode specification and Emacs source), and designed to run anywhere — locally, in CI, or from any editor.
This project was built with the help of AI tooling (Claude Code). The rule set was designed by studying org-lint.el and the org-mode specification.
- 9 format rules (auto-fixable): trailing whitespace, blank lines, heading spacing, table alignment, property drawer alignment, keyword spacing, tag alignment, list formatting, timestamp spacing
- 38 lint rules (report-only): structural validation (including
E003include-validityfor cross-file#+INCLUDE:directives), correctness checks, deprecation warnings, style suggestions — covering ~36 of Emacs org-lint’s ~58 checks - Protected regions: source, example, export, quote, verse, center, and comment blocks are never modified by format rules
- Configurable via
.org-tools.tomlwith sensible defaults matching Emacs
- Query language with predicates:
todo,done,tags,heading,body,property,priority,level,scheduled,deadline,closed,clocked,blocked,actionable,waiting - Boolean operators:
and,or,not, parentheses, implicit AND - Agenda view (
org query agenda): multi-day timeline (--from,--days,--warning-days,--composite) projecting+/++/.+repeaters,org-habit(:STYLE: habit) consistency graphs, overdue items, deadline warnings, and active body timestamps inhuman,json(JSON schema viaorg schema agenda),locator,org, andmd(-o) - Column view (
org query columns):#+COLUMNS:specification parser and bottom-up property/clock/effort rollup evaluator ({+},{min},{max},{mean},{:}) inhuman,json,org, andmd - Tag inheritance: child entries inherit parent tags in queries
- Output formats: human, JSON (with JSON schema), locator, Org, Markdown
A unique identifier for any heading across a tree of org files:
| Pattern | Example | Stability |
|---|---|---|
id:<uuid> | id:550e8400-e29b-... | Survives moves |
<file>::#<custom-id> | notes.org::#project-x | File-scoped |
<file>::*/<path> | todo.org::*/Work/Meeting | Fragile on rename |
<file>::<line> | inbox.org::42 | Fragile on edit |
When an entry has an :ID: property, that is always preferred.
- Active clocking:
org clock in,org clock out, andorg clock cancelmutations managing:LOGBOOK:CLOCK:timestamps - Reports & Effort Variance: total clocked time grouped by entry, tag, or day
with
:EFFORT:vs. clocked duration variance deltas - Date filtering:
--fromand--todate range - Running clocks: detect entries with open clock lines
- Output: human-readable tables and JSON
- add-id: add
:ID:properties to entries (UUIDv4, deterministic UUIDv5, template, or command) - set-state: change TODO keyword with automatic
CLOSEDtimestamps,:LOGBOOK:state transition logging (#+STARTUP: logdone/:LOGGING:),:LAST_REPEAT:recording, repeater auto-advance (--no-repeatto close permanently),:TRIGGER:cascades, and--queryfiltering - set-scheduled / set-deadline: set, shift (
today/.,+Nd,+Nw,+Nm,+Ny,-Nd), or--clearSCHEDULEDandDEADLINEtimestamps - add-todo: insert new entries with planning, priority, properties, and tags
- set-property / delete-property / set-tags / dep: drawer, tag, and
org-ednadependency mutations - add-cookie / calc: compute
[/]/[%]statistic cookies and#+TBLFM:formulas - refile (
org refile): move or copy subtrees across files or headings with automatic heading level adjustment and statistic cookie recalculation
- Scoped node extraction (
org show): extract headings or level-0org-roamfile nodes asorg,md, orjsonwith optional--expand-includes - Markdown export (
org export md): Zensical-ready GFM with Mermaid fences, cross-node[[id:...]]resolution, and--expand-includes(#+INCLUDE:with::*Heading,:minlevel N,:lines "A-B", and:only-contents t) - Calendar export (
org export ical,org export jscal): RFC 5545 iCalendar and RFC 8984 JSCalendar with date range and tag filtering
- Action navigator (
org next): find immediate unblocked next actions filtered by context, effort, energy, workmode, and project across vaults - GTD captures (
org roam gtd inbox,org roam gtd project): capture raw inbox tasks and scaffold project outlines without Emacs - Agenda synchronization (
org roam sync-agenda-tags): synchronize:agenda:filetags across vaults containing active TODO tasks
- Luhmann fleeting queue (
org fleeting): capture thoughts with source medium and location, list pending queues, reform into permanent concept notes, convert to tasks, discard, or interactively process - Atomic note capture (
org roam capture): create permanent notes via templates with automatic Folgezettel parent links and slug naming - Backlinks & graphs (
org roam node,backlinks,links,graph): query incoming links and export knowledge graph structures in Mermaid or JSON
- Built-in zero-Emacs JSON-RPC 2.0
stdioserver exposing 16 workspace-confined tools:org_roam_node,org_roam_backlinks,org_roam_search,org_roam_capture,org_fleeting_list,org_fleeting_transform,org_query_next,org_query_blocked,org_query_agenda,org_show,org_update_state,org_update_planning,org_clock_in,org_clock_out,org_refile, andorg_fmt_file - Incremental SQLite WAL + FTS5 cache (
.cache/org-cache.db) with warm telemetry
- Built-in zero-Emacs JSON-RPC 2.0
stdioserver (org lsp [--workspace <DIR>] [--roam-dir <DIR>]) - Editor capabilities: diagnostics, formatting, code actions, document symbols, document links, definition, backlink references, folding, completion, hover, workspace rename, and semantic tokens
- Ready out of the box with Neovim, Helix, VS Code, Zed, and Emacs
eglot
- Move done entries to an archive file with metadata properties
- Configurable target via
#+ARCHIVE:or--target - Preserves subtree structure and adds
:ARCHIVE_TIME:,:ARCHIVE_FILE:,:ARCHIVE_OLPATH:
# Install via Homebrew (macOS / Linux), Cargo, or run directly via GHCR container
brew install --cask lino/tap/org-tools
cargo install org-tools
docker run --rm -v "$PWD:/workspace" ghcr.io/lino/org-tools:latest fmt check README.org
# Lint
org fmt check file.org
# Format in place
org fmt format file.org
# Query entries
org query search 'todo:TODO tags:work' ~/org/
# Find immediate next action
org next --context @office --max-effort 1:00 --pick
# Capture fleeting thought and create permanent concept note
org fleeting capture "Atomic concept notes link by ID" --medium "Smart Notes"
org roam capture "Knowledge Architecture" --parent "Slip-Box"
# Agenda view and Zensical Markdown export
org query agenda ~/org/
org query agenda --from 2026-04-06 --warning-days 7 --composite --format md -o agenda.md ~/org/
# Set or shift planning dates
org update set-scheduled '+3d' 'id:550e8400-e29b-41d4-a716-446655440000'
org update set-deadline --clear 'id:550e8400-e29b-41d4-a716-446655440000'
# JSON output for tooling
org query search 'deadline:past' --format json ~/org/
# Clock report grouped by tag
org clock report ~/org/ --group-by tag
# Export scheduled items to iCalendar
org export ical ~/org/ -o calendar.ics
# Add IDs to all entries
org update add-id ~/org/
# Mark entries as DONE via piping
org query search 'todo:TODO tags:done' --format locator | org update set-state DONE
# Pipe org content through set-state with query filter
cat todo.org | org update set-state DONE --query 'tags:shipped'
# Archive completed entries
org archive ~/org/
# Start Language Server Protocol server for editor integration
org lsp --workspace ~/org/
# Shell completions, Unix manpages, and embedded JSON schemas
eval "$(org --completions zsh)"
org --completions fish | source
eval "$(org --completions bash)"
org --completions bash > /etc/bash_completion.d/org
man 1 org
man 5 org-tools.toml
org schema --list
org schema columns --output build/org-columns-output.schema.jsonCopy .org-tools.toml.example to .org-tools.toml in your project root:
[format]
trailing_whitespace = true
blank_lines = false
heading_blank_lines = false
table_format = true
property_drawer_align = true
[lint]
disabled_rules = []
[agenda]
deadline_warning_days = 14org-tools searches for .org-tools.toml starting from the current directory and
walking up to the filesystem root.
See docs/user/usage.org for the full usage guide and rule reference.
Requires Rust 1.70+ or use mise to install the pinned version:
mise install # install pinned Rust
mise run build # cargo build
mise run install # install org binary into ~/.cargo/bin
mise run test # cargo test
mise run lint # clippy + rustfmt + org fmt check
mise run hooks:install # install git pre-commit and pre-push hooksorg-tools is a Cargo workspace with two crates:
| Crate | Purpose |
|---|---|
org-tools-core | Shared library: rules, runner, config, OrgDocument, OrgLocator |
org | Umbrella binary: org fmt, org query, org clock, org update, org export, org archive |
Published via the Three-Manual Zensical site (zensical.toml, mise run docs:build)
and native Unix roff manpages (man/org.1 and man/org-tools.toml.5):
- docs/index.md — Three-Manual Zensical landing page
- docs/user/ & docs/cookbook/ — User Manual, Cookbook recipes, and usage.org
- docs/operations/ — Operator Manual (installation, Docker/MCP runtime, GoReleaser, Prometheus metrics)
- docs/developer/ & docs/technical/ — Developer Manual, Architecture (arc42), and ADRs
- docs/glossary.md — Alphabetical Glossary and Abbreviations
- docs/org-ecosystem.org — Org-mode ecosystem and extension reference
- schemas/ — JSON Schema Draft 2020-12 contracts (
org schema --list)
GPL-3.0-or-later. See LICENSE.
org-tools’s rule set was designed by studying org-lint.el and the org-mode specification. We chose GPL to respect the ecosystem that made this possible.