Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

184 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mado — markdown organizer

A command-line tool that stores entries (tasks, notes) as markdown files and supports powerful filtering with a query language

Features

  • Per-project isolation: Each project has its own MADO/ directory, similar to .git — no global directories are used. This allows you to version‑control MADO/ alongside your code
  • Entry storage: Entries stored as MAIN.md files in timestamped directories (YYYYMMDDTHHMMSS/MAIN.md) in MADO/ directory. The entry directory can also contain any additional files related to the entry — attachments, screenshots, logs, scripts, etc. Everything stays organized in one place

Usage Example

Start from scratch in a new project:

# Create a project directory and enter it
mkdir myproject
cd myproject

# Initialize MADO directory (like git init)
mado init

Once the MADO/ directory is initialized, you can work with entries from any subdirectory within the project — just like Git, mado automatically finds the nearest MADO/ directory by walking up the file tree

# Create your first entry
mado new

The entry will be created with the following content:

- NAME:
- PRIORITY:
- TAGS:
- STATUS:
- DEADLINE:

You can fill it out as needed, for example:

- NAME: Fix login bug
- PRIORITY: 10
- TAGS: bug, critical, auth
- STATUS: opened
- DEADLINE: 20260615

The login page returns 500 error when using special characters.
...

No fields are required — you can omit any field entirely or leave its value empty. For example, when writing a note, you probably won't need the priority, status and deadline fields. When a field is omitted or left empty:

  • NAME, STATUS default to empty string ""
  • PRIORITY defaults to 0
  • DEADLINE defaults to 99990000T000000
  • TAGS defaults to a list with one empty element [""]
  • TIME is a system field, always present and set to the entry's directory name (creation timestamp in YYYYMMDDTHHMMSS format). It cannot be changed or removed — it reflects when the entry was created
  • MTIME is a system field, automatically set to the modification time of the entry's file (YYYYMMDDTHHMMSS format). It updates whenever the entry file changes and cannot be manually edited

When you have many entries, you'll want to filter them:

# List all entries
mado list 'all'

# Find critical bugs
mado list 'tag = bug and priority > 5'

# Delete low priority entries
mado remove 'priority < 5'

# Filter by entry name (exact match)
mado list 'name = login'

# Filter by entry name (substring)
mado list 'name ~ login'
mado list 'name ~ "fix login"' # multiple words — quotes required

# Filter by creation time
mado list 'time ~ 20260516' # Entries created on 2026-05-16
mado list 'time > 20260516T12' # Entries created after 2026-05-16 12:00:00
mado list 'time > 2023 and time < @year+1' # Entries created between 2023 and current year (inclusive)

# Find entries with complex conditions
mado list '(tag = bug or tag = critical) and status = opened and deadline < @now'
mado list 'not (priority < 3 or status = closed)'
mado list '(priority > 5 and tag = urgent) or status = reopened'

# Syntactic sugar for matching multiple values
mado list 'status = anyof(opened, reopened)' # Status equals "opened" OR "reopened"
mado list 'priority = anyof(10, 20, 30)' # Priority equals 10 OR 20 OR 30
mado list 'tag = allof(bug, critical)' # Entry has BOTH "bug" AND "critical" tags

# Sort results
mado list -s +priority 'tag = bug' # bugs sorted by priority
mado list -s -priority,+time 'all' # highest priority first, newest first

Customizing Templates

Templates are stored in MADO/.templates/ as markdown files:

# Create a bug report template
cat > MADO/.templates/bug.md << 'EOF'
- NAME:
- PRIORITY: 10
- TAGS: bug
- STATUS: opened

## Steps to Reproduce
1.

## Expected Behavior

## Actual Behavior
EOF

You can create entries with custom templates:

mado new -t bug
# The template must exist at: MADO/.templates/bug.md

Sorting Entries

The -s / --sort flag allows you to sort entries by one or more fields:

# Sort by priority (ascending by default)
mado list -s priority 'all'

# Sort by priority descending
mado list -s -priority 'all'

# Sort by multiple fields (priority ascending, then time descending)
mado list -s +priority,-time 'all'

# Sort by status, then name
mado list -s status,name 'all'

Sort order:

  • +field or field — ascending order (default)
  • -field — descending order

Output Formats

The -f flag controls how entries are displayed:

# Default format: path:1: fields
mado list 'all'
# Compatible with Emacs compile buffer and other tools that parse file:line:

# Paths only — useful for piping to other tools
mado list -f path 'all'
# Search across entry bodies with grep
grep 'match' $(mado list -f path 'all')

# Newline-delimited JSON for scripts
mado list -f jsonl 'all'

# Pipe JSON output to jq for advanced processing
mado list -f jsonl 'priority > 5' | jq '.name'
mado list -f jsonl 'all' | jq -s 'group_by(.status)'
mado list -f jsonl 'all' | jq -s 'sort_by(.priority)'

Query Syntax

The query language supports filtering entries using operators and keywords

Operators

Operator Description
> Greater than
< Less than
>= Greater than or equal
<= Less than or equal
= Equal / exact match
!= Not equal
~ Contains
!~ Not contains

Logical Operators

Operator Description
and Logical AND
or Logical OR
not Logical NOT

Types

Type Description Format Examples
number Integer value 0-999 0, 10, 999
string Text value Unquoted: [a-zA-Z_][a-zA-Z0-9_-]* or quoted: "..." or '...' bug, "fix login", 'проблема'
timestamp Creation time of entry 4 digits, 6 digits or (8 digits + optional (T + 0, 2, 4 or 6 digits)) 2026, 20260516, 20260516T, 20260516T1230

Keywords

Keyword Type Operators Example
priority number >, <, >=, <=, =, !=, ~, !~ priority > 5, priority != 10
tag string >, <, >=, <=, =, !=, ~, !~ tag = bug, tag ~ crit
status string >, <, >=, <=, =, !=, ~, !~ status = opened, status ~ open
name string >, <, >=, <=, =, !=, ~, !~ name = "Fix bug", name ~ login
time timestamp >, <, >=, <=, =, !=, ~, !~ time > 20260505T1230 and time < 20260510T
mtime timestamp >, <, >=, <=, =, !=, ~, !~ mtime > 20260505T1230
deadline timestamp >, <, >=, <=, =, !=, ~, !~ deadline > 20260505T1230 and deadline < 20260510T
all special - all

Note: all operators also work with anyof(...) and allof(...). These are syntactic sugar that expand to multiple conditions. anyof(...) expands with or, allof(...) expands with and. Examples:

  • status = anyof(opened, reopened) is equivalent to status = opened or status = reopened
  • tag ~ allof(bug, crit, fix) is equivalent to tag ~ bug and tag ~ crit and tag ~ fix

Macros

Macros start with @ and are resolved at parse time — the value is substituted before the AST is evaluated.

Time Macros

Resolve to timestamps. Accept optional offsets with +/-

Macro Resolution Offset unit
@now Current timestamp days
@today Start of today days
@week Start of current week (Monday) weeks
@month Start of current month months
@year Start of current year years

Examples:

mado list 'deadline > @week'
mado list 'deadline > @year'
mado list 'time > @today-4'
mado list 'time >= @week-1'
mado list 'deadline < @today+30'
mado list 'time ~ @month-2'
mado list 'mtime > @now-1'

Installation

Clone the repository and build:

make

This will produce an executable file ./mado

Performance

Entries Peak memory usage
10,000 5.3 MB
20,000 10.5 MB
100,000 51.6 MB

Time to list 100,043 entries with filter query: ~7.2s

Note: benchmarked on AMD Ryzen 5 5600H (6 cores, 12 threads, 3.30 GHz base) with NVMe SSD

Requirements

  • Unix system (Linux, possibly macOS/BSD)
  • Build dependencies:
    • C compiler
    • C++ compiler
    • make
    • flex
    • bison

About

markdown organizer for Linux

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages