pub enum HelpTopic {
Root,
Daemon,
Init,
Cd,
Add,
Remove,
Monitored,
Query,
Clean,
}
pub const fn about(topic: HelpTopic) -> &'static str {
match topic {
HelpTopic::Root => "Lightweight high-performance file change tracking tool",
HelpTopic::Daemon => "Run the fsmon daemon (requires sudo for fanotify)",
HelpTopic::Init => "Initialize log and monitored data directories",
HelpTopic::Cd => "Open a subshell in the log directory",
HelpTopic::Add => "Add a path to the monitoring list",
HelpTopic::Remove => "Remove one or more paths from the monitoring list",
HelpTopic::Monitored => "List all monitored paths with their configuration",
HelpTopic::Query => "Query historical file change events from log files",
HelpTopic::Clean => "Clean historical log files, retain by time or size",
}
}
pub const fn long_about(topic: HelpTopic) -> &'static str {
match topic {
HelpTopic::Root => "",
HelpTopic::Daemon => {
r#"Run the fsmon daemon as a foreground process (requires sudo for fanotify).
The daemon monitors all configured paths via fanotify and logs events.
Use 'fsmon add'/'fsmon remove' to manage paths dynamically without
restarting the daemon.
Usage:
sudo fsmon daemon & Start daemon in background
sudo fsmon daemon --debug Enable debug output (event matching + cache stats)
sudo fsmon daemon --cache-dir-cap 200000 Override dir_cache capacity
sudo fsmon daemon --cache-proc-ttl 300 Override process cache TTL
fsmon add /path Monitor all events on /path
fsmon add openclaw --path /home -r Track openclaw on /home (recursive)
fsmon monitored List monitored paths
fsmon query -t '>1h' Query events from last hour
Config: ~/.config/fsmon/fsmon.toml
Monitored: ~/.local/share/fsmon/monitored.jsonl (configurable via [monitored].path)
Log dir: ~/.local/state/fsmon/ (configurable via [logging].path)
Socket: /tmp/fsmon-<UID>.sock (configurable via [socket].path)"#
}
HelpTopic::Init => {
r#"Initialize fsmon data directories (chezmoi-style).
Creates the default log directory and monitored data directory.
Config file at ~/.config/fsmon/fsmon.toml is optional — defaults
apply without it.
Created:
~/.local/state/fsmon/ Event log storage
~/.local/share/fsmon/ Monitored paths database
Examples:
fsmon init"#
}
HelpTopic::Cd => {
r#"Open a subshell in the log directory.
Spawns a new shell (using $SHELL, fallback /bin/sh) inside the
log directory. Type 'exit' to return to the original directory.
Examples:
fsmon cd Enter log directory in subshell
fsmon cd && ls List log files, then exit"#
}
HelpTopic::Add => {
r#"Add a path or process to the monitoring list.
The entry is added immediately if the daemon is running, and persisted
in the monitored paths database for automatic monitoring on daemon restart.
No sudo needed — store is updated immediately.
USAGE:
fsmon add [CMD] [OPTIONS]
ARGS:
<CMD> Process name to track (process tree + ancestry chain).
Enables process tree tracking: fork/exec children are auto-included.
When specified, matching events include a `chain` field.
Omit to monitor all events on a path (path-only mode).
Options:
--path <PATH> Filesystem path to monitor
-r, --recursive Watch subdirectories recursively
-t, --types Event types to monitor (repeatable; use "all" for all 14 types)
-s, --size Size filter with operator (required: >=, >, <=, <, =)
e.g. >1MB, >=500KB, <100MB, =0
Examples:
fsmon add openclaw --path /home -r Track openclaw on /home (recursive)
fsmon add nginx Track nginx globally (process-only)
fsmon add --path /home -r Monitor /home recursively (path-only)
fsmon add --path /home --types MODIFY --types CREATE Filter by event types
fsmon add --path /home --types all All 14 event types
fsmon add --path /home -s '>=1MB' Minimum file size change"#
}
HelpTopic::Remove => {
r#"Remove one or more paths from the monitoring list.
Without --path, removes the entire cmd group (including the null group).
With --path, removes only the specified paths. Multiple paths are atomic:
all must exist, or nothing is removed.
USAGE:
fsmon remove [CMD] [--path <PATH>...]
ARGS:
<CMD> Cmd group to remove (positional). Omit for null cmd group.
Options:
--path <PATH> Path(s) to remove from the cmd group (repeatable)
Examples:
fsmon remove Remove all paths from null cmd group
fsmon remove openclaw Remove the entire openclaw cmd group
fsmon remove openclaw --path /a Remove /a from openclaw group
fsmon remove --path /a --path /b Remove /a, /b from null cmd group (atomic)"#
}
HelpTopic::Monitored => {
r#"List all monitored paths with their configuration.
Displays each path with its recursive flag, event type filters,
size threshold, path/cmd exclusion patterns.
Examples:
fsmon monitored"#
}
HelpTopic::Query => {
r#"Query historical file change events from log files.
Output is JSONL (one JSON object per line), pipe to jq for custom filtering.
USAGE:
fsmon query [CMD] [OPTIONS]
ARGS:
<CMD> Cmd group to query (positional). Omit to query all cmd groups.
Log files are named by cmd: `{cmd}_log.jsonl` or `_global_log.jsonl`.
Options:
-p, --path Path prefix filter(s) applied to event.path. Repeatable.
-t, --time Time filter with operator (repeatable).
>1h — events newer than 1 hour ago (since)
<2026-05-01 — events before a date (until)
Combine both for a range: -t '>1h' -t '<now'
Alternatively, query the log files directly with standard Unix tools:
cat ~/.local/state/fsmon/*_log.jsonl | jq 'select(.cmd == "nginx")'
grep '"event_type":"MODIFY"' ~/.local/state/fsmon/*_log.jsonl
tail -f ~/.local/state/fsmon/*_log.jsonl | jq 'select(.user == "deploy")'
(Note: native fsmon query uses binary search and is significantly faster on large logs)
Examples:
fsmon query All events from all cmd groups
fsmon query openclaw Events from openclaw cmd group
fsmon query --path /home Events under /home (all cmd groups)
fsmon query nginx --path /var/www Nginx events under /var/www
fsmon query -t '>1h' Events from last hour"#
}
HelpTopic::Clean => {
r#"Clean a log file for a specific cmd group, retain by time or size.
Defaults: keep_days=30, size=>=1GB (from fsmon.toml [logging] section or code fallback).
CLI args override config. Daemon does not auto-clean; use cron/systemd timer.
USAGE:
fsmon clean <CMD> [OPTIONS]
ARGS:
<CMD> Cmd group to clean (positional). Use '_global' for the global log.
Options:
-t, --time Time filter with operator (e.g. >30d — keep newer than 30 days)
-s, --size Size limit for log file truncation with operator (e.g. >500MB, >=1GB).
Operator required: >=, >, <=, <, =
--dry-run Preview mode, don't actually delete
Alternatively, clean the log files directly with standard Unix tools:
truncate --size 100M ~/.local/state/fsmon/*_log.jsonl
for f in ~/.local/state/fsmon/*_log.jsonl; do tail -500 "$f" > "${f}.tmp" && mv "${f}.tmp" "$f"; done
find ~/.local/state/fsmon/ -name '*.jsonl' -mtime +30 -delete
(Note: native fsmon clean uses accurate JSONL parsing and is safer for large files)
Examples:
fsmon clean _global Clean global log with defaults (>=30d)
fsmon clean openclaw -t '>7d' Keep last 7 days of openclaw events
fsmon clean nginx --dry-run Preview nginx log cleaning"#
}
}
}
pub const fn after_help() -> &'static str {
r#"Use 'fsmon <COMMAND> --help' for detailed help
Setup (no sudo needed):
fsmon init Create log and monitored directories
fsmon cd Open subshell in log directory
Daemon (requires sudo):
sudo fsmon daemon & Start daemon in background
kill %1 Stop daemon (or Ctrl+C)
Management (no sudo needed):
fsmon add openclaw --path /home -r Track openclaw on /home (recursive)
fsmon add /path -r Monitor path (recursive, default 8 types)
fsmon remove Remove entire null cmd group
fsmon remove openclaw Remove entire openclaw cmd group
fsmon monitored List monitored paths
Query (stdout JSONL, pipe to jq):
fsmon query -t '>1h' Events from last hour
fsmon query | jq 'select(.cmd == "nginx")' Custom filter
cat ~/.local/state/fsmon/*_log.jsonl | jq ... Or direct pipe (slower)
Clean (config defaults: keep_days=30, size=>=1GB):
fsmon clean _global Clean global log (keep >30d)
fsmon clean openclaw -t '>7d' Keep last 7 days of openclaw
fsmon clean nginx --dry-run Preview nginx log cleaning
tail -500 ... Or direct Unix tools (slower)
Config: ~/.config/fsmon/fsmon.toml (optional — defaults without it)
Monitored: ~/.local/share/fsmon/monitored.jsonl (configurable via [monitored].path)
Logs: ~/.local/state/fsmon/*_log.jsonl (configurable via [logging].path)"#
}