Skip to content

Repository files navigation

lazynote

CI GitHub Releases GitHub tag

lazynote is a local, terminal-first notes app for developer workflows.

Take notes instantly from the CLI, browse them in a small TUI, and expose the same notes to shell scripts, terminal tools, and coding agents. It is built for quick context capture without an account, server, database, or sync service.

Notes are stored locally as JSON. The released binary does not require a Go toolchain.

Contents

Why lazynote?

  • Capture notes from arguments, stdin, and shell pipelines.
  • Retrieve context with plain commands such as list, show, search, and export.
  • Share one local notes file between humans, scripts, and coding agents.
  • Browse notes in a fast terminal UI when you want a human view.

Quick Example

# take simple note: $ lazynote <title> <body>
lazynote showerthought 'Running from the cops is the ultimate double or nothing.'

# tag a note while capturing it
lazynote --tag work idea 'Use a single notes file so agents and humans share context.'

# piped body with an inferred title
printf '## Session abc123\n- fixed flaky test\n' | lazynote

# retrieve context
lazynote list
lazynote search flaky
lazynote search '#work'
lazynote export json

lazynote TUI screenshot

Install and Update

Recommended for installing or updating to the latest release on Linux and macOS:

curl -fsSL https://raw.githubusercontent.com/rschoch/lazynote/main/install.sh | sh

The same command handles both installation and updates. It downloads the latest release, verifies checksums when possible, and installs or replaces lazynote in ~/.local/bin.

Confirm the installed version afterward:

lazynote --version

If your shell cannot find it:

export PATH="$HOME/.local/bin:$PATH"

Inspect the installer first:

curl -fsSLO https://raw.githubusercontent.com/rschoch/lazynote/main/install.sh
sh install.sh

Installer options:

sh install.sh --dir /usr/local/bin
sh install.sh --version vX.Y.Z

Uninstall a script-installed binary:

rm -f ~/.local/bin/lazynote

Prebuilt archives and Linux .deb, .rpm, and .apk packages are available on the GitHub Releases page. Direct downloads do not add an apt/yum/apk repository, so package-manager auto-updates are not configured yet.

From source:

go install github.com/rschoch/lazynote/cmd/lazynote@latest

From a checkout:

make build
make install

make install uses /usr/local by default. Use PREFIX for another root:

make install PREFIX="$HOME/.local"

CLI Workflows

Capture a note:

lazynote idea 'Use a single notes file so agents and humans share context.'
lazynote --tag work --tag idea idea 'Keep note metadata small and useful.'

Capture from stdin:

echo 'Refactor release notes before tagging the next release.' | lazynote release
cat summary.md | lazynote 'session summary'
lazynote 'session summary' - < summary.md

If stdin is piped without a title, the first non-empty line becomes the title:

printf '## Session abc123\n- shipped release prep\n' | lazynote

Suppress success output for scripts and agents:

some-command | lazynote --quiet 'session summary'
lazynote --quiet release 'Tag after CI passes.'

Retrieve context:

lazynote list
lazynote show <id>
lazynote show --body <id>
lazynote search packaging
lazynote search '#work'
lazynote backup
lazynote export markdown
lazynote export json
lazynote path

list prints tab-separated id, created_at, and title fields, plus a metadata field when a note is pinned, archived, or tagged. show accepts a full ID or a unique ID prefix.

Manage existing notes:

lazynote edit <id>
lazynote edit <id> 'new title' 'new body'
lazynote edit <id> 'new title' - < body.md
lazynote delete <id>
lazynote pin <id>
lazynote pin --toggle <id>
lazynote unpin <id>
lazynote archive <id>
lazynote unarchive <id>
lazynote tag <id> work idea
lazynote untag <id> work
lazynote tags <id>

edit <id> opens $VISUAL, $EDITOR, or vi. Direct edit commands replace the title and body without opening an editor. tag normalizes tags to lower-case names and accepts optional leading #.

Search is case- and accent-insensitive, so queries such as cafe match Café. CLI list, search, show, and export commands include archived notes; archived entries are marked in summaries and exports. The TUI filters them into its Archived view instead.

Convenience aliases are rm for delete, show -b for show --body, and export md for export markdown. -h and -v are short forms of --help and --version.

backup prints the backup file path. With no path it writes a timestamped JSON copy under a backups directory next to the notes file. Pass a file path to choose the exact destination, or an existing directory for a timestamped backup inside that directory.

Command words such as list, show, search, edit, delete, rm, pin, unpin, archive, unarchive, tag, untag, tags, path, backup, export, help, and version are reserved when they are the first argument. Use -- to use one as a title:

lazynote -- search 'a note whose title is search'

Use single quotes for literal shell text, especially if the note contains characters like !, $, or backticks.

Agent Plugins

Agent plugins are optional. The lazynote CLI works on its own; plugins only teach tools like Codex or Claude Code how to save and retrieve notes through the CLI. Install the lazynote binary first, then install the plugin for your agent.

Both agent skills append a small source conversation footer to new notes, with the agent, session name when known, session ID, project directory, and resume command (codex resume <id> or claude --resume <id>). Unavailable fields are omitted. The footer is ordinary note text and stays visible in exports; resuming requires the original agent's saved conversation to still be available.

Codex Install

Add the GitHub marketplace source. This does not require cloning lazynote first:

codex plugin marketplace add rschoch/lazynote

Then open /plugins in Codex and install lazynote, or install it directly:

codex plugin add lazynote@lazynote

To pick up newer plugin instructions later, upgrade the marketplace source and update the installed plugin from /plugins:

codex plugin marketplace upgrade lazynote

Ask Codex to use lazynote when you want it to persist or retrieve project context:

"Use lazynote to save the proposed implementation plan."
"Search lazynote for notes about release packaging."
"Save a summary of this debugging session to lazynote."

Claude Code Install

Add the GitHub marketplace source, install the plugin, and reload plugins. This does not require cloning lazynote first:

/plugin marketplace add rschoch/lazynote
/plugin install lazynote@lazynote
/reload-plugins

To pick up newer plugin instructions later, update the marketplace, reinstall the plugin, and reload if Claude Code asks you to:

/plugin marketplace update lazynote
/plugin install lazynote@lazynote
/reload-plugins

Invoke the namespaced Claude Code skill with /lazynote:lazynote:

/lazynote:lazynote Save the proposed implementation plan.
/lazynote:lazynote Search for notes about release packaging.
/lazynote:lazynote Save a summary of this debugging session.

TUI

Open the terminal UI:

lazynote

The TUI shows note titles on the left and the selected note body on the right. It automatically reloads when the notes file changes, so notes added from another terminal tab, script, or coding agent appear while the TUI stays open. The bottom status line shows context-specific key hints.

Keys:

  • left: focus note list
  • right: focus note body
  • down: move or scroll down in the active pane; the note list wraps to the top
  • up: move or scroll up in the active pane; the note list wraps to the bottom
  • Home/End: jump to the first/last note or the top/bottom of the note body
  • g/G: jump to the first/last note
  • PageDown: scroll note body down
  • PageUp: scroll note body up
  • /: case- and accent-insensitive filter by title, body, or #tag; Enter applies, Esc cancels; matching title and body text is highlighted
  • r: reload notes from disk now
  • n: create a note in $VISUAL, $EDITOR, or vi
  • e: edit the selected note in $VISUAL, $EDITOR, or vi
  • p: pin or unpin the selected note
  • t: add or remove tags; Space toggles, Enter saves, and n creates a tag
  • a: archive the selected note, or restore it from the Archived view
  • v: choose Active, Pinned, Recent, Untagged, Archived, or a #tag view
  • ?: show or hide the help overlay
  • c: copy the selected title or note body
  • C (Shift+C): copy the selected note ID and display it in the status line
  • d / delete: arm deletion; press d again to confirm
  • Esc: clear the active filter
  • q / Ctrl-C: quit

Copy uses the native macOS clipboard when available and terminal clipboard support on Linux, WSL, and Windows. To point an agent to an existing note, press Shift+C and paste the ID into your prompt; the agent can read it with lazynote show <id>. Creating and editing open a temporary file whose first line is the note title and whose remaining content is the note body. The default Active view hides archived notes. Archiving also clears the note's pin. Use v to open the view picker; Recent contains the 50 newest active notes, and tag views match exact tags. Tags have no separate registry: a tag disappears when no note uses it. Tags used only by archived notes remain available in the tag picker but do not get their own active tag view. The note body pane shows tags and edited timestamps when present. Pinned notes stay at the top of the list and use in the list gutter. Notes that arrive from another process while the TUI is open use until selected. http:// and https:// URLs are highlighted in note bodies; opening them uses the terminal's native Ctrl/Cmd-click behavior. Fonts, glyph rendering, and colors depend on your terminal emulator. Note bodies wrap at word boundaries using terminal display widths, including wide and combining Unicode characters.

Set your preferred external editor before launching lazynote:

export VISUAL="nvim"
export EDITOR="nano"

VISUAL is preferred over EDITOR; if neither is set, lazynote falls back to vi. GUI editors should wait for the file to close, for example VISUAL="code --wait".

TUI Behavior

TUI behavior is configured in ~/.config/lazynote/config.json:

{
  "tui": {
    "refreshIntervalSeconds": 1,
    "noteOrder": "oldest-first",
    "autoSelectNewNotes": false
  }
}

Supported values:

  • refreshIntervalSeconds: how often the open TUI checks for external changes
  • noteOrder: oldest-first or newest-first
  • autoSelectNewNotes: jump to newly arrived notes after auto-refresh

Themes

The TUI includes adaptive default, mono, and high-contrast themes, plus fixed dark and light themes. The default inherits your terminal's foreground and background colors, so it remains readable with either a light or dark terminal profile.

LAZYNOTE_THEME=light lazynote

Custom theme overrides are configured in ~/.config/lazynote/config.json. See THEMING.md for the full format and examples.

Storage

Default notes file:

~/.local/share/lazynote/notes.json

Print the active path:

lazynote path

Use a different notes file:

LAZYNOTE_PATH=/tmp/lazynote-dev.json lazynote list

Back up your notes:

lazynote backup
lazynote backup ~/backup/lazynote
lazynote backup ~/backup/lazynote/notes.json

Because storage is one JSON file, it can be synced with tools like Syncthing, Dropbox, iCloud Drive, or a private dotfiles repository. The TUI reloads when the file changes, including atomic replacements. Writes use a small lock file next to the notes file so concurrent CLI, TUI, script, and agent writes do not silently overwrite each other. Newer versions may write optional tags, updated_at, pinned, and archived fields; older notes without these fields continue to load normally.

Development

Run tests and build a dev binary:

make test
make build
bin/lazynote --version

Try the dev binary without touching your real notes:

LAZYNOTE_PATH=/tmp/lazynote-dev.json bin/lazynote 'dev smoke' 'hello from local build'
LAZYNOTE_PATH=/tmp/lazynote-dev.json bin/lazynote list
LAZYNOTE_PATH=/tmp/lazynote-dev.json bin/lazynote export markdown
LAZYNOTE_PATH=/tmp/lazynote-dev.json bin/lazynote

If go is installed but not on PATH:

make GO=/usr/local/go/bin/go test
make GO=/usr/local/go/bin/go build

Check the installer script:

sh -n install.sh
sh install.sh --help

Useful targets:

  • make build: build bin/lazynote
  • make test: run go test ./...
  • make install: install under $(PREFIX)/bin
  • make uninstall: remove from $(PREFIX)/bin
  • make clean: remove local build and release artifacts
  • make release-snapshot: build local GoReleaser artifacts

Roadmap

See ROADMAP.md for lightweight future candidates and deliberately deferred ideas.

Releases

GoReleaser configuration lives in .goreleaser.yaml. Tagged releases build Linux, macOS, and Windows binaries for amd64 and arm64, plus checksums, archives, and Linux packages.

Create a local snapshot:

make release-snapshot

Publish a tagged release:

git tag vX.Y.Z
git push origin vX.Y.Z

GitHub Actions runs tests and publishes release artifacts. Publishing apt/yum/apk repositories or Homebrew taps is a separate distribution step.

Acknowledgements

lazynote takes a lot of inspiration from LazyGit, especially around keeping a terminal UI fast, keyboard-driven, and practical without making it feel heavy.

License

MIT

Releases

Packages

Contributors

Languages