mps-rs 1.8.0

MPS — plain-text personal productivity CLI (Rust)
Documentation

mps

Crates.io CI License: MIT

A plain-text personal productivity CLI. Journal your day as tasks, notes, reminders, logs, and character entries in simple .mps files. Search, list, tag, and export them. Sync across devices via git. Chat with your journal through any local or remote LLM. Single binary, no runtime dependencies.


Install

cargo install mps-rs

The installed binary is named mps.

From source

git clone https://github.com/mash-97/mps-rs
cd mps-rs
cargo install --path .

Quick start

mps init                                     # first-run setup wizard
mps                                          # open today's file in $EDITOR
mps list                                     # print today's elements
mps list --since monday                      # all elements since last Monday
mps append task "Fix the auth bug" --tags work,backend
mps append note "The edge case only appears under load"
mps append reminder "Team standup" --at 3pm
mps append log "Deep-work session" --start-time 09:00 --end-time 11:30
mps append character "Helped me think through the design" --name "Dr. Alice" --tags mentor
mps done task-1                              # mark task-1 done
mps edit note-1                              # rewrite note-1's body in $EDITOR
mps delete task-3 --yes                      # delete task-3 without confirmation
mps search "auth" --since "last week"
mps stats --since monday
mps export --format csv --since "20260501" > may.csv
mps autogit                                  # stage + commit + pull + push
mps notify --dry-run                         # preview due reminders + open tasks
mps daemon install                           # enable minutely background checker
mps meta show                                # inspect cross-device config layer
mps meta sync up                             # push YAML settings → .mps.meta
mps meta sync down                           # pull .mps.meta settings → YAML
mps chat                                     # chat with your journal via local LLM
mps chat -s mywork                           # named session: resume or start
mps serve                                    # start REST API on http://127.0.0.1:3000
mps serve --port 8080 --token mysecret       # custom port + Bearer auth

Element types

Type Description
task Something to do, with open/done status
note Free-form observation or thought
reminder Time-anchored alert
log Timed work block (start/end time → duration)
character Running monologue about a person

Commands

mps init

Interactive first-run setup wizard. Prompts for your journal directory, git settings, default command, and LLM chat URL/model. Creates ~/.mps_config.yaml and all required directories.

mps init            # guided setup
mps init --force    # overwrite existing config without confirmation prompt

If a config already exists you are prompted to confirm before overwriting. Typing y, Y, yes, or YES proceeds; anything else aborts.


mps [open] [DATE]

Open the .mps file for DATE in $EDITOR (falls back to vim). Creates the file if absent.

mps                   # today
mps open yesterday
mps open last friday

mps list [DATE]

Print elements for DATE as an indented tree.

Flag Short Description
--type TYPE -t Filter by type: task, note, log, reminder, character
--tag TAG -g Filter by tag name
--status STATUS -s Filter tasks by open or done (hides all non-task elements)
--name NAME -n Filter character entries by person name
--since DATE -S Show elements from DATE up to the target date
--refs -r Show human-readable ref column (task-1, mps-1.2, …)
--all -a List across the entire archive, not just one date
mps list
mps list --type task --status open
mps list --since monday --refs
mps list --all --name "Dr. Alice"

mps append TYPE BODY [FLAGS]

Append one element to today's file without opening an editor. TYPE is resolved through type_aliases from config (e.g. ttask).

Flag Description
--tags t1,t2 Comma-separated tags
--status open|done Task status (default: open)
--at TIME Time for reminders (5pm, 10:30, …)
--start-time HH:MM Start time for logs
--end-time HH:MM End time for logs
--name NAME -n Person name for character entries
mps append task "Review the PR" --tags work,backend
mps append note "Cache invalidation approach"
mps append reminder "1:1 with manager" --at 2pm
mps append log "Debugging session" --start-time 14:00 --end-time 16:30
mps append character "Explained the system clearly" --name "Mahfuz Vai" --tags mentor,work
mps append task "Write tests" --status done --tags ci

mps edit REFPATH [--date DATE]

Open an element's body text in $EDITOR. The body is written to a temp file; on save the original file is updated atomically. No-op if the content is unchanged.

mps edit task-1
mps edit note-2 --date yesterday
mps edit 20260601.1779000000.1   # epoch ref works too

mps delete REFPATH [FLAGS]

Remove an element entirely from its file. Prompts for confirmation unless --yes is given.

Flag Short Description
--yes -y Skip confirmation prompt
--date DATE -d Date context for human refs (default: today)
mps delete task-1
mps delete note-3 --yes
mps delete task-2 --date yesterday

mps update REFPATH [FLAGS]

Update one element's attributes in-place. REFPATH is a human ref (task-1, mps-1.2) or an epoch ref (20260428.1732500287.1).

Flag Description
--status open|done Set task status
--start-time HH:MM Set log start time
--end-time HH:MM Set log end time
--at TIME Set reminder time
--date DATE -d Date context for human refs (default: today)
mps update task-1 --status done
mps update mps-1.2 --end-time 17:00
mps update task-3 --status done --date yesterday

mps done REFPATH [--date DATE]

Shorthand for mps update REFPATH --status done.

mps done task-1
mps done task-2 --date yesterday

mps search QUERY [FLAGS]

Full-text search across all .mps files. Returns matching elements with date and ref.

Flag Short Description
--type TYPE -t Filter by element type
--tag TAG -g Filter by tag
--name NAME -n Filter character entries by person name
--since DATE -S Search from DATE onward
mps search "auth"
mps search "design" --type character --name "Dr. Alice"
mps search "deploy" --since "last week" --type log

mps stats [DATE] [FLAGS]

Show element counts and total log durations.

Flag Short Description
--since DATE -S Stats from DATE up to target date
--all -a Stats across the entire archive
mps stats
mps stats --since monday
mps stats --all

mps tags [DATE] [FLAGS]

Show tag usage as a frequency bar chart.

Flag Short Description
--type TYPE -t Count tags for this element type only
--status STATUS -s Restrict to tasks with this status
--name NAME -n Restrict to character entries for this person
--since DATE -S Tags from DATE up to target date
--all -a Count across the entire archive
mps tags
mps tags --all --type task --status open
mps tags --since monday --name "Dr. Alice"

mps export [DATE] [FLAGS]

Export elements to stdout as JSON or CSV.

Flag Short Description
--format json|csv -f Output format (default: json)
--type TYPE -t Filter by element type
--since DATE -S Export from DATE up to target date

CSV columns: date, ref, type, tags, body, status, at, start, end, name

mps export --format json
mps export --format csv --since "20260501" > may.csv
mps export --since monday --type log

mps config [SUBCOMMAND]

View, edit, or validate configuration.

Subcommand Description
show (default) Print all active config values
edit Open config file in $EDITOR
init Write every config key explicitly to the YAML file (idempotent, no prompts)
check Validate config health — paths exist, aliases are valid, chat URL reachable
mps config           # same as mps config show
mps config show
mps config edit      # opens config file in $EDITOR
mps config init      # materialise all keys into the YAML (safe to run any time)
mps config check     # validate; exits non-zero if anything is wrong
mps config check --no-network   # skip the chat URL TCP reachability check

mps config check prints a ✓/✗ line per item and exits non-zero if any check fails, making it suitable for scripting:

Config health check
  /home/you/.mps_config.yaml

  ✓  mps_dir     : /home/you/.mps
  ✓  storage_dir : /home/you/.mps/mps
  ✓  log_file    : /home/you/.mps/mps.log
  ✓  type_aliases   : t→task, n→note
  ✓  command_aliases: a→append, l→list
  ✓  chat.url       : http://localhost:11434 (reachable)

  ✓  all checks passed

mps notify [FLAGS]

Check for due reminders and open tasks, then send desktop notifications via notify-send.

Flag Description
--dry-run Print what would be sent without actually sending
--window MINS Override the due-now window in minutes (default: from config)
--force Fire even if already notified within the window

Reminders fire when the current time falls within window_minutes of the reminder's --at time. Each reminder is deduplicated by its ref so it won't re-fire until the cooldown has elapsed.

Open-task briefing fires once per day at task_notify_at time (e.g. "9am"), listing all open tasks from today plus up to overdue_days past days.

mps notify --dry-run
mps notify --force              # re-fire even if already sent
mps notify --window 10          # 10-minute window

Notification settings live in ~/.mps_config.yaml under the notify: key or in .mps.meta for cross-device sync (see Meta config).


mps daemon SUBCOMMAND

Manage a systemd user timer that calls mps daemon run (= mps notify) once per minute.

Subcommand Description
install Write unit files, enable and start the timer
remove Stop and disable the timer, remove unit files
status Pass-through to systemctl --user status mps-notify.timer
run Run one notify tick (invoked by systemd; also safe to call manually)
mps daemon install
mps daemon status
mps daemon remove

Unit files are written to ~/.config/systemd/user/. .mps.local (notification history) is automatically added to .gitignore on install so it stays off git.


mps meta [SUBCOMMAND]

Inspect or edit the .mps.meta sidecar config file.

Subcommand Description
show (default) Pretty-print .mps.meta and .mps.local
edit Open .mps.meta in $EDITOR
clear Delete .mps.local (notification history + cache)
sync up Push machine-agnostic settings from YAML config → .mps.meta
sync down Pull settings from .mps.meta → YAML config file
mps meta            # same as mps meta show
mps meta edit
mps meta clear
mps meta sync up    # YAML → .mps.meta, then run: mps autogit
mps meta sync down  # .mps.meta → YAML (machine-specific paths unchanged)

sync up reads your current ~/.mps_config.yaml and writes all machine-agnostic fields (type_aliases, command_aliases, default_command, custom_tags, notify, and non-sensitive chat fields: url, model, context_days, stream) into .mps.meta. Run mps autogit afterwards to push the update to other devices.

sync down reads .mps.meta and applies its fields into your local YAML config file. Machine-specific paths (storage_dir, mps_dir, log_file) and chat.api_key are never touched. Both subcommands respect --config-path.


mps chat [FLAGS]

Interactive REPL that loads recent journal entries into an LLM's context window and lets you ask natural-language questions about them. Works with any OpenAI-compatible endpoint — Ollama, llama.cpp, OpenAI API, or any compatible provider.

Flag Short Description
--url URL LLM base URL (default: auto-detect :11434 then :8080)
--model MODEL Model name (default: llama3.2)
--api-key KEY Bearer token for keyed APIs (empty = no auth)
--context-days N Days of history to load (default: 7)
--since DATE Load journal from DATE onward (overrides --context-days)
--all Load entire journal history
--stream BOOL Stream tokens as they arrive (default: true)
--session-name NAME -s Named session: resume if it exists, start new if not
--new Force a fresh session even if a named one already exists
--list-sessions Print all saved sessions and exit
mps chat                              # one-off chat with last 7 days of journal
mps chat --context-days 30            # wider context window
mps chat --all                        # entire archive as context
mps chat -s standup                   # named session (auto-saved after each reply)
mps chat -s planning --new            # force-start a fresh "planning" session
mps chat --list-sessions              # show all saved sessions
mps chat --url http://localhost:11434 --model gemma4:e4b
mps chat --url https://api.openai.com/v1 --api-key sk-... --model gpt-4o

How it works

Each session builds a system prompt from scratch using your journal entries — formatted with date headers and element badges ([task], [note], [log], …). The prompt is rebuilt on every load so new entries appear automatically, even when resuming an old session.

Sessions are saved to ~/.mps/sessions/NAME.json after each assistant response and are git-tracked (so they sync across devices with mps autogit). api_key is never written to session files or to .mps.meta.

REPL commands

Command Description
:help List available commands
:context Print the current system prompt (your journal entries)
:reload Rebuild context from disk (picks up entries added since session started)
:session Show session name, message count, last saved
:sessions List all saved sessions
:save [NAME] Save current session (to current name or NAME)
:save-as NAME Save a copy under a new name and switch to it
:load NAME Load a saved session (replaces current message history)
:clear Clear conversation history, keep session name and context
:quit / :exit Exit (auto-saves if session is named)

LLM backend auto-detection

If --url is not set, mps probes http://localhost:11434 (Ollama) then http://localhost:8080 (llama.cpp). Set chat.url in your config or .mps.meta to pin a specific endpoint.


mps git ARGS / mps autogit / mps cmd ARGS

Run git or shell commands inside the storage directory.

mps git status
mps git auto          # add . + commit + pull + push
mps git autocommit    # add . + commit only
mps autogit           # same as mps git auto
mps cmd ls -la        # any shell command in storage dir

mps serve [FLAGS]

Start an Axum HTTP server that exposes all mps operations as a JSON REST API. Designed for browser tooling, mobile clients, and AI integrations.

Flag Short Description
--port PORT -p TCP port to listen on (default: 3000)
--host HOST Host address to bind (default: 127.0.0.1)
--token TOKEN -t Bearer token for API auth; empty string = no auth
mps serve                          # http://127.0.0.1:3000, no auth
mps serve --port 8080              # custom port
mps serve --port 3000 --token abc  # require Authorization: Bearer abc

Endpoints

Method Path Description
GET /health {"status":"ok","version":"1.8.0"}
GET /elements List elements (?date, ?type, ?tag, ?since, ?all=true)
POST /elements Append element; returns {"ref":"...","human_ref":"..."} (201)
PATCH /elements/:ref Update attributes in-place; returns {"updated":true}
DELETE /elements/:ref Delete element; returns {"deleted":true}
GET /search Full-text search (?q, ?type, ?tag, ?since)
GET /stats Element counts + log durations (?date, ?since, ?all=true)
GET /export Export as JSON or CSV (?format=json|csv, ?date, ?since, ?type)
GET /tags Tag frequency map (?date, ?type, ?all=true)

All responses are JSON. CORS is permissive (any origin). Auth is skipped when token is empty.

Browser UI

Opening http://localhost:3000/ in any browser loads a fully self-contained single-page app — no CDN, no external dependencies, works offline against the local server.

Feature Details
Today tab Live stats pills, append form (all 5 types with per-type fields), type/tag filter, element count indicator
Search tab Full-text + type/tag/since filters, auto-focused on tab switch
Archive tab Date picker with ‹ › navigation
Tags tab Frequency bar chart, type filter, all-dates toggle
Stats tab Big-number cards, task completion bar, dates-covered chips
Edit modal Inline body + attribute editing, empty-body validation
Font size A− / A / A+ controls, 3 levels, persisted in localStorage
Font family Sans / Serif / Mono button group, persisted in localStorage
Theme 🌙 / ☀️ toggle, dark (default) and light, persisted in localStorage
Keyboard 1–5 switch tabs, n new entry, / search, Ctrl+Enter submit form, Esc close
curl http://localhost:3000/health
curl http://localhost:3000/elements?all=true
curl -X POST http://localhost:3000/elements \
     -H "Content-Type: application/json" \
     -d '{"type":"task","body":"ship it","tags":["work"]}'
curl -X PATCH http://localhost:3000/elements/20260525.1 \
     -H "Content-Type: application/json" \
     -d '{"status":"done"}'
curl "http://localhost:3000/export?format=csv&since=20260501" > may.csv

Server settings can also live in ~/.mps_config.yaml under the serve: key — see Configuration.


mps version

Print the version string.


File format

Files are named YYYYMMDD.<epoch>.mps (or YYYYMMDD.mps for older files without an epoch suffix).

@task[work, release, status: done]{
  Ship the API refactor
}

@note{
  The auth token expiry edge case only appears under concurrent load
}

@reminder[at: 3pm]{
  Team standup
}

@log[work, start: 09:00, end: 11:30]{
  Debugging the auth flow
}

@character[name: Dr. Alice, mentor, trusted]{
  Explained the layered caching approach in detail.
  Would consult again for architecture decisions.
}

@mps[sprint-42]{
  @task[backend]{
    Nested task inside a sprint block
  }
  @note{
    Retrospective note
  }
}

Brackets are optional — @task{ body } is valid. Tags and named attributes share the bracket: [tag1, tag2, status: done, at: 5pm].


Date formats

Accepted everywhere a DATE is expected:

Input Meaning
today Today
yesterday Yesterday
mondaysunday Most recent occurrence of that weekday
last friday The Friday before the most recent one
3 days ago 3 days before today
last week 7 days ago
20260421 Explicit YYYYMMDD
2026-04-21 Explicit YYYY-MM-DD

Configuration

Config file: ~/.mps_config.yaml. Created automatically on first run, or interactively via mps init. Run mps config init at any time to ensure all keys are explicitly present.

mps_dir: /home/you/.mps
storage_dir: /home/you/.mps/mps
log_file: /home/you/.mps/mps.log
git_remote: origin
git_branch: master
default_command: list    # command run by bare `mps` invocation (open or list)

# Short-hand element type aliases
type_aliases:
  t: task
  n: note
  r: reminder
  l: log
  c: character

# Short-hand command aliases
command_aliases:
  a: append
  "+": append
  s: search
  l: list

# Canonical tag list synced across devices via .mps.meta
custom_tags:
  - work
  - personal
  - urgent

# Desktop notification settings
notify:
  enabled: true
  window_minutes: 5         # minutes either side of a reminder time counts as "due"
  task_notify_at: "9am"     # morning briefing time; omit to disable open-task briefing
  notify_open_tasks: true
  open_task_tags: []        # if non-empty, only tasks with these tags are included
  task_cooldown_minutes: 60 # min gap between repeat notifications for the same reminder
  overdue_days: 7           # how many past days to scan for overdue open tasks

# HTTP API server settings (machine-specific, not synced via .mps.meta)
serve:
  port: 3000
  host: 127.0.0.1
  token: ""              # empty = no auth; set to require Bearer token

# LLM chat settings
chat:
  url: null              # null = auto-detect :11434 (Ollama) then :8080 (llama.cpp)
  model: llama3.2
  context_days: 7
  stream: true
  api_key: ""            # Bearer token for keyed APIs (OpenAI, etc.) — never synced
  sessions_dir: null     # null = ~/.mps/sessions/

With the above config:

  • mps a t "Fix the bug" --tags work → appends a task (aappend, ttask)
  • mps + n "Interesting observation" → appends a note
  • mps s "auth" → searches for "auth"

Override the config path:

mps --config-path /path/to/other.yaml list
# or
MPS_CONFIG=/path/to/other.yaml mps list

Note: Legacy symbol-key YAML configs (:storage_dir: /path) are normalised transparently on load.


Meta config

.mps.meta is a JSON sidecar file at ~/.mps/mps/.mps.meta that is git-tracked and synced across all your devices via mps autogit. It acts as a second config layer — machine-agnostic settings you want consistent everywhere.

Fields supported (union-merged with ~/.mps_config.yaml at startup; meta wins for scalars, maps are unioned with YAML taking priority on key conflicts):

{
  "version": 1,
  "config": {
    "type_aliases":    { "t": "task", "c": "character" },
    "command_aliases": { "a": "append", "+": "append" },
    "default_command": "list",
    "custom_tags":     ["work", "personal", "urgent", "health"],
    "notify": {
      "enabled":               true,
      "window_minutes":        5,
      "task_notify_at":        "9am",
      "notify_open_tasks":     true,
      "open_task_tags":        [],
      "task_cooldown_minutes": 60,
      "overdue_days":          7
    },
    "chat": {
      "url":          "http://myserver:11434",
      "model":        "llama3.2",
      "context_days": 7,
      "stream":       true
    }
  }
}

chat.api_key and chat.sessions_dir are never written to .mps.meta — they stay local.

Edit it directly with mps meta edit. Inspect the current state with mps meta show. Use mps meta sync up to push your YAML settings into the file, and mps meta sync down to pull the shared settings back into your local YAML.

.mps.local (also in ~/.mps/mps/) holds per-device transient state (notification history, cache). It is gitignored and never committed.


Architecture

src/
  main.rs         Entry point — alias pre-processing, clap dispatch
  cli.rs          Cli + Commands (#[derive(Parser)])
  config.rs       Config + ChatConfig + ServeConfig; YAML load/save/init; merge_meta()
  meta.rs         MetaShared (.mps.meta) + MetaLocal (.mps.local) + ChatMetaConfig
  time_parse.rs   parse_time() — "5pm", "9:30am", "17:00", "noon"
  constants.rs    Filename regexes, new_file_name()
  date_parse.rs   parse_date() — natural-language + absolute formats
  error.rs        MpsError (thiserror)
  parser.rs       Position-based stack parser
  ref_resolver.rs Bidirectional epoch ↔ human ref (task-1, mps-1.2)
  store.rs        Store — all filesystem I/O; append, parse, search, rewrite
  api/            JSON request/response types + helpers for the REST API
  elements/       Element enum + per-type Data structs
  llm/
    mod.rs        LlmClient — OpenAI-compatible streaming SSE client; auto_detect()
    context.rs    build_system_prompt() — formats journal entries for LLM context
    session.rs    ChatSession — save/load/list named sessions (JSON, atomic write)
  commands/
    chat.rs       mps chat REPL — session lifecycle, rustyline loop, REPL commands
    config_cmd.rs mps config show/edit/init/check (inc. tcp_reachable health check)
    init_cmd.rs   mps init interactive wizard
    serve.rs      Axum router, Bearer auth middleware, all HTTP handlers
    …             one module per remaining command + shared display helpers

Two sidecar files live in storage_dir (~/.mps/mps/):

File Tracked Purpose
.mps.meta Git-tracked Second config layer — aliases, notify settings, chat settings, custom tags
.mps.local Gitignored Per-device state — notification history, cache

Chat sessions live in ~/.mps/sessions/ (git-tracked; path configurable via chat.sessions_dir).


Requirements

  • Rust 1.70+
  • git (for git / autogit commands)
  • $EDITOR or $VISUAL (for open / config edit / meta edit; falls back to vim)
  • notify-send (for mps notify / mps daemon — Linux desktop notifications; optional)
  • LLM for mps chat: Ollama (local, recommended), llama.cpp server, or any OpenAI-compatible API endpoint (optional)

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md for development setup, test instructions, and the PR checklist. If you have an idea or found a bug, please open an issue first so we can discuss before you start coding.


Changelog

v1.8.0 (2026-05-27)

  • mps chat — interactive LLM chat REPL using your journal as context
    • Loads recent entries into a system prompt (context stuffing, rebuilt fresh every session load)
    • OpenAI-compatible streaming API: works with Ollama, llama.cpp, OpenAI, and any compatible endpoint
    • Auto-detects local Ollama (:11434) or llama.cpp (:8080) when no URL is configured
    • Named sessions persisted to ~/.mps/sessions/NAME.json, git-tracked, auto-saved after each reply
    • api_key is local-only — never written to session files or .mps.meta
    • REPL commands: :context, :reload, :session, :sessions, :save, :save-as, :load, :clear, :help, :quit
    • CLI flags: --url, --model, --api-key, --context-days, --since, --all, --stream, --session-name/-s, --new, --list-sessions
  • mps init — interactive first-run setup wizard
    • Prompts for journal dir, storage dir, git remote/branch, default command, LLM URL and model
    • Creates config file and all required directories; warns if config already exists
    • Accepts y/Y/yes/YES to confirm overwrite; --force skips the prompt
  • mps config init — idempotent, non-interactive: writes every config key (including the full chat: block) explicitly to the YAML file; safe to run any time
  • mps config check — validates config health:
    • Checks mps_dir, storage_dir, log_file exist
    • Validates type_aliases resolve to known element types; command_aliases resolve to known commands
    • TCP-checks chat.url reachability (skip with --no-network); HTTPS defaults to port 443
    • Exits non-zero on any failure; ✓/✗ per item
  • mps config show — now prints the full chat: section (url, model, context_days, stream, api_key masked, sessions_dir)
  • mps meta sync up/down — now includes non-sensitive chat fields (url, model, context_days, stream); api_key and sessions_dir explicitly excluded
  • ChatConfig in config.rs (local-only: url, model, context_days, stream, api_key, sessions_dir)
  • ChatMetaConfig in meta.rs (synced: url, model, context_days, stream only)
  • Total tests: 943 (47 new integration tests for init/config init/config check)

v1.7.7 (2026-05-27)

  • CI fix: resolved all Clippy warnings-as-errors (-D warnings) and rustfmt formatting failures
  • Total tests: 896

v1.7.6 (2026-05-25)

  • Fix: Editing a task and setting status to done without changing the body text incorrectly returned 404 "ref not found"
  • Fix (defense-in-depth): saveEdit() in the browser UI now only includes body in the PATCH payload if the value actually changed from what was fetched

v1.7.5 (2026-05-25)

  • Fix (critical): init was not exported in the public API — App.init() threw TypeError on load, silently breaking the entire browser UI
  • Fix: light-mode hover on element items was invisible
  • Fix: font-family <select> replaced with Sans / Serif / Mono button group
  • UX: Search tab auto-focuses; Ctrl+Enter submits form; Edit modal validates non-empty body; Today filter shows element count; raw 422 errors replaced with human-readable messages

v1.7.4 (2026-05-25)

  • Font family selector: Sans, Serif, Mono; persisted in localStorage

v1.7.3 (2026-05-25)

  • Comprehensive UI revision: CSS variable–based font scaling, custom scrollbar, smooth focus rings, fadeDown animation, blur backdrop on modal
  • Font size controls (A− / A / A+) persisted in localStorage
  • Colored left-border accent stripe per element type; redesigned stat pills; task completion progress bar
  • Keyboard hints footer

v1.7.2 (2026-05-25)

  • Light/dark theme toggle (🌙/☀️) persisted in localStorage

v1.7.1 (2026-05-25)

  • Browser UI served at GET / — no external dependencies, fully self-contained dark-theme SPA
  • GET /elements/:ref — fetch a single element by epoch or human ref
  • PATCH /elements/:ref now accepts body field for in-place body text editing

v1.7.0 (2026-05-25)

  • mps serve — Axum HTTP server with 9 JSON endpoints, Bearer token auth, CORS
  • Browser SPA with Today/Search/Archive/Tags/Stats tabs, dark theme, keyboard shortcuts
  • ServeConfig in ~/.mps_config.yaml; 50 new tests

v1.6.2 (2026-05-25)

  • mps meta sync up / mps meta sync down — push/pull machine-agnostic settings via .mps.meta

v1.6.1 (2026-05-24)

  • Fix reminder deduplication cooldown, merge_meta() field-by-field notify merge, mps edit body dedenting, meta JSON validation, notify briefing line cap
  • 559 tests total

v1.6.0 (2026-05-24)

  • mps edit REFPATH — open element body in $EDITOR, atomic write-back
  • mps delete REFPATH [--yes] — remove element with confirmation

v1.5.0 (2026-05-06)

  • mps notify, mps daemon — desktop notifications via systemd user timer
  • mps meta — cross-device config layer (.mps.meta / .mps.local)

License

MIT