Skip to content

laserattack/mado

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

156 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

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 unix format: path:1: fields
mado list 'all'
MADO/20260521T204844/MAIN.md:1: TIME:[20260521T204844] NAME:[...] PRIORITY:[10] DEADLINE:[99990000T000000] STATUS:[closed] TAGS:[feat,flag]
# 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'
# MADO/20260516T161611/MAIN.md
# Search across entry bodies with grep
grep 'match' $(mado list -f path 'all')

# Newline-delimited JSON for scripts
mado list -f jsonl 'all'
# {"time":"20260521T204844","name":"...","priority":10,"deadline":"99990000T000000","status":"closed","tags":["feat","flag"],"path":"MADO/20260521T204844/MAIN.md"}
# 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
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

Query language supports macros that expand to values at execution time. Macros start with @

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'

Installation

Clone the repository and build:

make

This will produce an executable file ./mado

Requirements

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

About

markdown organizer

Resources

License

Stars

Watchers

Forks

Contributors