Markdown Base CLI (markbase)
A high-performance CLI tool for indexing and querying Markdown notes, designed for both AI agents and human users with Obsidian compatibility in mind.
Installation
Prerequisites: Rust 1.85+ (DuckDB is bundled)
Quick Start
Environment Variables
| Variable | Description | Default |
|---|---|---|
MARKBASE_BASE_DIR |
Vault directory | . (current directory) |
MARKBASE_OUTPUT_FORMAT |
Output format for query/template list | table |
Priority: CLI args > Environment variables > Defaults
Concepts
Note Properties
Each indexed note has two property types:
Reserved Fields (native metadata):
| Field | Type | Description |
|---|---|---|
path |
TEXT | File path relative to base-dir |
folder |
TEXT | Directory path relative to base-dir |
name |
TEXT | File name without extension |
ext |
TEXT | File extension |
size |
INTEGER | File size in bytes |
ctime |
TIMESTAMPTZ | Created time |
mtime |
TIMESTAMPTZ | Modified time |
tags |
VARCHAR[] | Tags from content (#tag) and frontmatter |
links |
VARCHAR[] | Wiki-links [[link]] + embeds ![[embed]] from body and frontmatter |
backlinks |
VARCHAR[] | Notes linking to this note (reverse of links) |
embeds |
VARCHAR[] | Embeds ![[embed]] from body only |
Frontmatter Properties: Any YAML frontmatter field is queryable:
---
title: My Note
author: John
status: in-progress
---
Query it directly: markbase query "author == 'John'"
Field Resolution
Reserved fields are checked first. If a frontmatter field conflicts with a reserved field (except tags), it's ignored with a warning during indexing.
Name Uniqueness
Note names must be unique across the entire vault, regardless of their directory location.
- Index: When indexing, if two notes have the same name (different paths), a warning is shown and the duplicate is skipped
- Create: Creating a note fails if a note with that name already exists
- Rename: Renaming a note fails if a note with the target name already exists
Link Format (Obsidian Style)
Always use the filename only — no path, no extension:
[[中国移动]]
[[张三]]
[[entities/中国移动.md]]
[[people/张三]]
Wiki-links in frontmatter properties must additionally be wrapped in quotes:
# ✅ Correct
related_customer: "[[中石油]]"
attendees_internal:
# ❌ Wrong
related_customer:
attendees_internal:
Commands
index
Index Markdown notes to DuckDB.
Features:
- Incremental updates (skips unchanged files)
- Detects and removes deleted files
- Obsidian-compatible (wiki-links, embeds, frontmatter, tags)
query
Query indexed notes.
Two input modes:
# Expression mode (WHERE clause only)
# SQL mode (full SELECT statement)
Output formats:
Debug:
Type casts for non-string comparisons:
note
Create and manage notes.
Create a note:
Rename a note:
Behavior:
- Looks up note by name (not path)
- Fails if name is ambiguous or new name exists
- Updates all
[[old-name]]links and![[old-name]]embeds across the vault (body and frontmatter) - Preserves aliases, section anchors, and block IDs
template
Manage MKS templates.
Templates are stored in templates/ under base-dir.
Query Syntax
markbase translates field names (reserved fields and frontmatter properties) to DuckDB queries. All DuckDB SQL keywords and operators are supported natively.
Commonly Used Functions:
list_contains(field, value)- Array containment
Examples:
License
MIT