Scripting and the shell

Scripts, editors and coding agents all drive the same ntropy command line. This page is the plain-text side: the non-interactive mode, writing a note from a script, reading the output, and the ncd shell function.

Non-interactive mode

Pass -n (--non-interactive) and ntropy drops the interactive parts: no picker, no editor, no prompt, only plain text on stdout. Piping alone does not do that. ntropy stays interactive as long as it can reach your terminal, so scripts and command substitutions must say -n. Where no terminal exists, as under cron or CI, the same happens on its own.

Write a note from a script

ntropy new --empty creates a note's file with no content in it: ntropy picks the ULID, the location and the file name, and the text is yours to write. ntropy write stores a note's whole text from stdin, then realigns the file name, refreshes the views and prints the resulting path. The two author a note without an editor and without reading anything back, in a plaintext and an encrypted vault alike:

note=$(ntropy new --empty -p Quarterly review)
ntropy write "$note" <<'EOF'
---
title: Quarterly review
tags: [work, planning]
---
# Quarterly review

Numbers go here.
EOF

write takes the whole note, frontmatter first, and refuses text that is not a well-formed note. It names its target, a full ULID, the note's file name, or its path in all-notes/, and never searches for it, so it opens no picker and asks no question. Until frontmatter lands in an --empty file, the file is not a well-formed note, and ntropy skips it with a warning. --template is refused alongside --empty.

The note table

search -n prints one note per line as a space-aligned ID DATE TITLE TAGS PATH table. Each column is padded to its widest cell in Unicode display width and separated from the next by two or more spaces. The last column stays unpadded, so no line carries trailing whitespace. Rows are newest first, tags are comma-joined, and an uppercase header row leads the output. tags and view list print headers too.

Split it with awk -F' +', a field separator of two or more spaces: awk -F' +' '{print $1}' prints the ID column, and tail -n +2 drops the header. One caveat: a title with doubled spaces is printed verbatim, so a cell can hold a two-space run that shifts the fields after it. Treat TITLE and the columns after it as best-effort. ID and DATE never contain spaces and are always safe.

A control character in a cell, such as a line break or an escape character in a title or file name, is shown escaped as \n or \u{1b}, and so are the bidirectional override and isolate characters. A row stays one line, and a cell cannot send commands to your terminal, also when the vault came from someone else.

Paths and content

File paths need no parsing at all. search -n -p prints every match as one path per line (ntropy search -n -p tag:work | xargs grep -l deadline), and new -p and today -p print the created note's path.

A path is printed exactly as it is on disk. A path that holds a control or bidi character would act on your terminal, so it is not printed at all. A command that prints one path fails instead. search -n -p leaves such a path out with a warning, prints the rest and exits non-zero. ntropy reconcile renames such a note to its canonical name.

To read a note rather than locate it, search -P (--print-content) writes its text to stdout, for exactly one note. It reads the same in an encrypted vault, where -p names the ciphertext file; see Encrypted vaults, which also covers --identity and --passphrase-file for scripts.

ntropy search -n -P 01J8Z9K…            # the note, either kind of vault
for id in $(ntropy search -n tag:work | tail -n +2 | awk '{print $1}'); do
    ntropy search -n -P "$id"
done

show -n is not the way to a note's text. It prints the note laid out for reading: plain text when stdout is a pipe, wrapped at 80 columns or at --width, with the Markdown markers gone. Use it to display a note, and -P to process one.

Exit codes

A search that matches nothing exits non-zero, so if ntropy search -n tag:urgent; then … branches on "did anything match" without parsing a single line. delete under -n asks nothing, so it refuses to run without -f (--force). Where a note has to be named back to you, as in a delete prompt or an ambiguous match, it appears as date title [tags] (id).

Shell integration

ntropy info --print prints the active vault's path and nothing else, always absolute. That is the hook for shell functions, and the repository ships one for bash and zsh: contrib/shell/ntropy.sh defines ncd, which changes directory to the active vault.

# In ~/.bashrc or ~/.zshrc, from a checkout of the repository
source /path/to/ntropy/contrib/shell/ntropy.sh

# Installed with Homebrew, the formula has put the script here
source "$(brew --prefix)/opt/ntropy/share/ntropy/ntropy.sh"
ncd                   # cd to whichever vault is active here
ncd --vault ~/notes   # or name one; every global flag is forwarded

It has to be a shell function rather than an ntropy cd subcommand, because a process cannot change its parent shell's working directory. An unresolvable vault leaves the shell where it was. A cargo install or a downloaded binary does not put the script on disk, so source it from a checkout of the repository.