sapphire-journal-cli 0.12.0

Markdown-based task and note manager that keeps your data alive as plain text - timeless like fossils
sapphire-journal-cli-0.12.0 is not a library.

sapphire-journal

Unified binary for sapphire-journal — a Markdown-based task and note manager. Provides both the CLI for humans and an MCP server for AI agents.

Installation

Install script (Linux / macOS)

curl -fsSL https://raw.githubusercontent.com/fluo10/sapphire-journal/main/install.sh | sh

Install script (Windows)

irm https://raw.githubusercontent.com/fluo10/sapphire-journal/main/install.ps1 | iex

From crates.io

cargo install sapphire-journal

From source

cargo install --path .

CLI usage

Initialize a journal

sapphire-journal init [PATH]

Creates .sapphire-journal/config.toml with the detected local timezone and .sapphire-journal/.gitignore.

Global options

# Override journal root (also settable via SAPPHIRE_JOURNAL_DIR env var)
sapphire-journal --journal-dir /path/to/journal <command>

Entry commands

Create a new entry

sapphire-journal entry new --title <TITLE> [--body "body text"] [OPTIONS]

Options:

  • --slug SLUG — override the filename slug
  • --tags tag1,tag2 — set tags
  • --task-due DATETIME — set task due date
  • --task-status STATUS — set task status (open | in_progress | done | cancelled | archived)
  • --event-start DATETIME, --event-end DATETIME

The filename is auto-generated as {year}/{grain-id}_{slug}.md.

Create and edit in $EDITOR

sapphire-journal entry edit --new

Opens $EDITOR ($VISUAL$EDITORvi) with a pre-filled frontmatter template. On save, the filename is adjusted to match the title.

List entries

sapphire-journal entry list [PATH] [OPTIONS]

Timestamp filters (OR'd across fields):

sapphire-journal entry list [PERIOD]      # positional PERIOD applies to all timestamp fields
--task-due PERIOD             # filter by task due date
--event-span PERIOD           # filter by event span overlap (in-progress events included)
--created-at PERIOD           # filter by created_at
--updated-at PERIOD           # filter by updated_at
--all-periods                 # match entries regardless of period

PERIOD formats: today | yesterday | this_week | last_week | this_month | last_month | YYYY-MM-DD | YYYY-MM-DD,YYYY-MM-DD | YYYY-MM-DDTHH:MM,YYYY-MM-DDTHH:MM

Task state filters:

--task-overdue                # tasks whose due date is past and not closed
--task-in-progress            # tasks currently in_progress
--task-unstarted              # tasks with status open and no started_at
--active                      # composite: overdue OR in-progress

Other filters (AND'd on top):

--task-status open,in_progress   # comma-separated status values
--tags work,urgent               # entry must have ALL specified tags

Sort:

--sort-by FIELD    # id | title | task_status | created_at | updated_at | task_due | event_start | event_end
--sort-order asc   # or desc (default: asc)

Output:

--json   # output all matching entries as JSON (metadata + body)

Display entries as a tree

sapphire-journal entry tree [PATH] [OPTIONS]

Displays entries in a parent-child hierarchy based on parent_id in frontmatter. Supports the same filter and sort options as entry list.

--json   # output the tree as JSON (nested children arrays)

Show an entry

sapphire-journal entry show <file-or-id>

Edit an entry

sapphire-journal entry edit <file-or-id>

Opens the entry in $EDITOR.

Update frontmatter fields

sapphire-journal entry modify <file-or-id> --title "New title"
sapphire-journal entry modify <file-or-id> --tags work,backend
sapphire-journal entry modify <file-or-id> --tags          # clear all tags
sapphire-journal entry modify <file-or-id> --task-status done

When --task-status is set to done, cancelled, or archived, closed_at is set automatically.

Check and fix filename

sapphire-journal entry check <file-or-id>   # report any filename/frontmatter mismatches
sapphire-journal entry fix <file-or-id>     # rename file to match frontmatter

Remove an entry

sapphire-journal entry remove <file-or-id>

Cache commands

sapphire-journal cache info       # show cache status and statistics
sapphire-journal cache sync       # incrementally update the cache
sapphire-journal cache rebuild    # drop and rebuild the cache from scratch

DATETIME format

YYYY-MM-DD or YYYY-MM-DDTHH:MM.

For deadline/end timestamps (--task-due, --event-end), date-only input is interpreted as 23:59. For start/close timestamps (--event-start, --task-closed-at), date-only input is interpreted as 00:00.

Journal configuration

.sapphire-journal/config.toml:

[journal]
timezone = "Asia/Tokyo"   # IANA timezone name
# week_start is deprecated — ISO weeks (Monday start) are always used

MCP server

The MCP (Model Context Protocol) server now ships as a separate sapphire-journal-mcp binary in the sapphire-journal-mcp crate. Install it alongside the CLI to let AI agents (Claude, etc.) read and write journal entries.

Start the server

# Open the journal found by walking up from the current directory
sapphire-journal-mcp

# Open an explicit journal path
sapphire-journal-mcp --journal-dir /path/to/journal

# Create the journal (and the directory itself) if it doesn't exist, then open it
sapphire-journal-mcp --journal-dir /path/to/journal --init

The server fails to start when the target directory is not a sapphire-journal — pass --init to have the server create one in place (no-op when one already exists there).

Flags and environment variables

Flag / Variable Description
--journal-dir <DIR> / SAPPHIRE_JOURNAL_DIR Path to the journal root. If not set, the server walks up from the current directory to find .sapphire-journal/.
--init Initialize the target directory as a sapphire-journal if it isn't one already (and create the directory itself if missing).

Example: Claude Desktop

{
  "mcpServers": {
    "sapphire-journal": {
      "command": "sapphire-journal-mcp",
      "env": {
        "SAPPHIRE_JOURNAL_DIR": "/path/to/your/journal"
      }
    }
  }
}

Available tools

Tool Description
entry_list List entries as JSON with filtering and sorting
entry_tree List entries as a nested JSON tree (parent-child hierarchy)
entry_show Show the contents of an entry by ID prefix or file path
entry_new Create a new journal entry
entry_modify Update frontmatter fields of an existing entry
entry_check Validate an entry's frontmatter and filename
entry_fix Rename an entry file to match its frontmatter
entry_remove Delete an entry file
entry_search Search entries (vector when embeddings are enabled, FTS otherwise)
cache_info Show cache status and statistics
cache_sync Incrementally update the SQLite cache
cache_rebuild Drop and rebuild the cache from scratch
git_sync Commit, fetch, merge, and push if a sync backend is configured

entry_list parameters

Timestamp filters are OR'd across fields; task_status and tags are AND'd on top.

Parameter Description
period Shorthand: applies to all timestamp fields
task_due Filter by task due date
event_span Filter by event span overlap: matches entries whose event [start, end] overlaps the period
created_at Filter by created_at
updated_at Filter by updated_at
task_overdue Include tasks whose due date is past and not closed
task_in_progress Include tasks currently in_progress
task_unstarted Include tasks with status open and no started_at
active Composite: overdue OR in-progress
task_status Array of statuses to include, e.g. ["open", "in_progress"]
tags Array of tags; entry must have ALL specified tags
sort_by Field to sort by: id | title | task_status | created_at | updated_at | task_due | event_start | event_end
sort_order "asc" (default) or "desc"

PERIOD format: today | this_week | this_month | yesterday | last_week | last_month | YYYY-MM-DD | YYYY-MM-DD,YYYY-MM-DD | YYYY-MM-DDTHH:MM,YYYY-MM-DDTHH:MM

License

MIT OR Apache-2.0