Welcome to my personal site. In addition to the posts you see below, feel free to explore other places where I stash content here. The now page is an occasionally-updated page about long-term plans and activities. I try to post several times a week and those updates appear on the journal page. Sometimes I post tidbits about things I learn in the til page. More info in: toolkit, readings, to learn, gallery, colophon, and changelog.

Using Obsidian Linter plugin to update YAML modified date

I’ve written twice in the blog about keeping the modification date (mdate:) in the YAML frontmatter of my Obsidian notes up to date. I no longer use either of those methods. Instead, I use the Linter plugin, which handles this inside Obsidian.

The earlier approaches

In November 2022, I described using fswatch to update note metadata. A shell script watched the vault for filesystem changes, read each changed note’s modification time with stat, and used sed to write that value into its YAML frontmatter. The script also had to filter out temporary files and unrelated events, and it needed to keep running in the background as a launchd user agent.

By May 2023, I was using a Hazel rule to trigger a similar shell script. In my discussion of file creation dates, I discussed a complication: rewriting a note with sed -i changed its filesystem creation date. The workaround used GetFileInfo to save the original creation date and SetFile to restore it after updating the YAML. Those utilities required the Xcode command line tools.

Both approaches put the responsibility for maintaining Obsidian metadata in tools outside Obsidian. There is now a much simpler way to handle this.

Using Linter

In Linter’s settings, open the YAML tab and find YAML Timestamp. Enable Date Modified. To keep using the field from my earlier examples, set Date Modified Key to mdate. The format YYYY-MM-DD HH:mm matches those examples as well. See the YAML timestamp documentation for the available options.

Linter settings with Date Modified enabled, mdate as the YAML key, File system as the source of truth, and YYYY-MM-DD HH:mm as the format
Linter's Date Modified settings, configured to update the mdate field using the file system as the source of truth.

The timestamp rule needs to run for the value to update. You can run Linter manually, or enable Lint on save in its general settings to run it when you explicitly save a note. Linter also offers Update YAML Timestamp on File Contents Update for updating the timestamp after edits to the active note; select an interval rather than Never if you want that behavior. The instructions for running rules explain the available triggers.

For me, the main advantage is that the solution lives inside Obsidian. Beyond the Linter plugin itself, it requires no external resources: no filesystem watcher, Hazel rule, background shell script, or developer utilities. The configuration stays with the application where I write the notes, and there is considerably less to maintain.

Usually simpler is better.

If you have questions or comments, please get in touch via my contact page.

Setting up a multi-purpose iTerm2 profile for development

With time, I’ve come to prefer working more inside the terminal than in macOS GUI applications. This is particularly true when using agents to assist with tasks related to what I’m doing. For example, when writing for this blog, I usually keep a codex session going so that I can take advantage of it to do tasks like inserting images in the right way, linking to product URLs, cross-linking posts, etc. (No, I do not use LLM agents to write the text of this blog.) Both for coding and for writing, I’ve developed a tmux configuration that keeps everything in one terminal screen to reduce the amount of application and window switching.

The following script sets up my terminal session just the way I want it. A codex session runs on the left, and the top right is available for editing with vim and related tasks. The bottom right is a session that watches changes in the repository. Alternatively, it could just be used for repository management without the watch feature.

#!/bin/zsh

SESSION="blog"
DIR="$HOME/Documents/blog/ojisan"

set -e

# Create the layout only when the session does not already exist.
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
    # Create the session/window in the project directory.
    tmux new-session -d -s "$SESSION" -n main -c "$DIR"

    # Split into left and right halves.
    tmux split-window -h -t "$SESSION:main" -c "$DIR"

    # Split the right pane into upper and lower panes.
    tmux split-window -v -t "$SESSION:main.1" -c "$DIR"

    # Lower-right pane: continuously show git diff.
    tmux send-keys -t "$SESSION:main.2" \
        "watch -n 1 --color 'git status --short --untracked-files=all; echo; git diff --color=always; git diff --cached --color=always'" C-m
fi

# Start Codex in a new pane, or restart it when an existing pane is at a shell.
# Leave Codex (or any other foreground program) alone if it is already running.
LEFT_PANE="$SESSION:main.0"
case "$(tmux display-message -p -t "$LEFT_PANE" '#{pane_current_command}')" in
    zsh|bash|sh|fish|dash|ksh)
        tmux send-keys -t "$LEFT_PANE" 'codex' C-m
        ;;
esac

# Focus the Codex pane.
tmux select-pane -t "$SESSION:main.0"

# Attach.
tmux attach-session -t "$SESSION"

I use this code in an iTerm2 profile (Profiles > Command > /bin/zsh -lc '/Users/alan/Documents/dev/tmux-sessions/ojisan-tmux') so that when I select Profiles > ojisan, my session is set up exactly the way I want every time. The result looks something like this:

iTerm2 tmux development layout with Codex on the left, Vim at the upper right, and repository changes at the lower right

That’s it. Just something that makes my life 0.1% less irritating.

If you have questions or comments, please get in touch via my contact page.