Install and setup

How the jotura command line tool reaches your PATH on each platform, how it picks a vault, and what its global flags and exit codes do.

jotura is the command line interface to the same vault the desktop app uses. Vault files are plain markdown on disk, so there is no unlock step and no daemon to start. Every data command works the moment the binary is on your PATH and a vault is selected.

This page covers getting the binary installed, checking that it works, telling it which vault to use, and the flags and exit codes that apply to every command. The individual commands are documented in the rest of this section, starting with reading and searching.

The CLI ships inside the desktop app

There is no separate CLI download. Every desktop installer carries the jotura binary next to the app executable. You can get the installers from the download page. How the binary reaches your PATH depends on the platform.

Platform Where the binary lands How it reaches your PATH
macOS (.dmg or .app) Jotura.app/Contents/MacOS/jotura Open Settings, go to Advanced, and use the Command-line tool card. Installing creates /usr/local/bin/jotura as a symlink to the bundled binary, through an admin-privileged step, so macOS asks for your password.
Windows (.msi) <install dir>\jotura.exe The MSI adds its install folder to the system PATH during installation. The command resolves in any new terminal with no further action.
Linux (.deb) /usr/bin/jotura Already on the standard PATH. Nothing to install.
Linux (AppImage) Inside the AppImage, under usr/bin/ The Command-line tool card copies the binary to ~/.local/bin/jotura. That directory has to be on your PATH for the command to resolve.

Windows PATH

The MSI adds the install folder to the system PATH, so jotura resolves in any terminal you open after installing. Already-open terminals need a restart to pick the change up. If the app’s Settings card offers to install the command-line tool even though jotura already works in your terminal, you can decline: the command is available either way.

The Settings card and the startup prompt

The Command-line tool card is rendered only on the platforms that need it, which are macOS, Windows, and the Linux AppImage. A .deb install never shows it. On Windows the card writes your user PATH through the environment API directly rather than using setx, because setx truncates long PATH values. If that write fails, the card surfaces the error text from PowerShell, or the literal message Could not update PATH. when PowerShell reported nothing.

On Windows and the AppImage the app also shows a one-time startup prompt offering to do the same job as the card. It is skipped entirely when the status already says installed, which is why most people never see it. The app records that it asked whichever way you answer, so the prompt does not return, and from then on the Settings card is the way to install. The settings reference covers the rest of that panel.

To remove the tool later, undo whichever route installed it:

sudo rm /usr/local/bin/jotura
rm ~/.local/bin/jotura

On Windows, edit PATH under System Properties, then Environment Variables.

The one-line installer

If you would rather do the whole thing from a terminal, an install script handles it. Both scripts perform the same five steps:

  1. Fetch the release manifest from releases.jotura.io.
  2. Download the installer artifact for your operating system and CPU.
  3. Verify the artifact’s SHA-256 checksum against the manifest before touching anything.
  4. Install the desktop app and put the jotura CLI on your PATH.
  5. Launch the app.

The scripts write nothing to your AI agents’ files, and no flag makes them. You add the Jotura skills separately, as described under Adding the Jotura skills.

On macOS and Linux:

curl -fsSL https://jotura.io/install.sh | bash

On Windows, in PowerShell:

irm https://jotura.io/install.ps1 | iex

Both scripts are readable before you run them. The links open the raw script files rather than pages: install.sh and install.ps1. Rerunning either one upgrades an existing install in place. If a script fails at any point it tells you to fall back to the download page.

What each platform ends up with

The phrase “install the app and put the CLI on your PATH” means something different on each platform, and only one of the three is fully automatic.

Platform App location CLI location Privileges needed
macOS /Applications/Jotura.app, with the quarantine flag cleared Symlink at /usr/local/bin/jotura sudo for the symlink, and also for the app copy when /Applications is not writable by your user
Linux, AppImage (default) ~/.local/share/jotura/Jotura.AppImage, plus an icon and a jotura.desktop menu entry Copied to ~/.local/bin/jotura None
Linux, --deb System package, launched as jotura-desktop /usr/bin/jotura sudo, and the install fails without it
Windows Install folder chosen by the MSI jotura.exe in that folder, on the system PATH A Windows UAC elevation prompt from msiexec /passive

Three privilege details are worth knowing before you run anything. On macOS, the script prints that sudo is needed because /usr/local/bin is system-owned, and if sudo is unavailable or declined it only warns: the CLI then stays inside the app bundle and off your PATH. On Linux with --deb, sudo is a hard requirement and the script stops with advice to rerun without --deb for a user-level AppImage install. On the AppImage path the script warns when ~/.local/bin is not on your PATH, and prints the export PATH=... line for your shell profile, but adding it is your job.

One more Linux tradeoff: the AppImage auto-updates itself from inside the app, and the .deb does not. To upgrade a .deb install, rerun the script.

On Windows, already-open terminals need restarting before they see the new PATH. If msiexec returns code 3010, the script treats the install as successful and reports that Windows wants a reboot to finish.

Installer flags

The macOS and Linux script accepts flags after -s --:

Flag Effect
--no-launch Do not launch the app when the install finishes.
--deb Linux only. Install the .deb system package instead of the AppImage.
-h, --help Print the script’s help and exit.

For example, to install without launching the app:

curl -fsSL https://jotura.io/install.sh | bash -s -- --no-launch

The PowerShell script takes a parameter rather than a flag. Piping into iex cannot carry it, so either download the file and run it, or wrap the piped script as & ([scriptblock]::Create((irm https://jotura.io/install.ps1))) -NoLaunch:

Parameter Effect
-NoLaunch Do not launch the app when the install finishes.

Adding the Jotura skills

The skills teach an agent when and how to run the jotura commands. They live in the jotura-agents repository on GitHub. In Claude Code, add the marketplace and install the plugin from inside a session:

/plugin marketplace add adamrichardson14/jotura-agents
/plugin install jotura@jotura-agents

Codex, Gemini CLI, GitHub Copilot, OpenCode, Cursor, Windsurf and Cline all read skills or rules from their own locations. Copy the SKILL.md files and their references from the repository into the place your agent reads. Either way the skills need the jotura binary on PATH.

Jotura never writes to an agent’s config. Your instruction files are yours to write however you like, and an installed skill stays as you left it until you update it yourself.

Check that it worked

Open a new terminal window so it picks up the updated PATH, then ask for the version:

jotura --version

The output is the command name followed by the version number, for example jotura 0.11.1. That version comes from the binary itself, so it tells you which build you are running.

Then confirm the command surface loads:

jotura --help

If either command is not found, the PATH change has not reached that shell yet. Close the terminal, open a fresh one, and try again.

When the CLI is older than the app

A CLI left over from an older install can be a full release behind the app, which matters because commands are added over time. The memory family, for instance, does not exist in 0.6.1. Three things help:

  • Run jotura doctor, which reports both cli-version (the running binary) and desktop-app-version (read from the desktop settings file). Seeing them side by side is the quickest way to confirm a mismatch.
  • On macOS, the Settings card’s button reads Reinstall once a tool is present. When the symlink no longer points at the current app bundle, the status line reads Installed at <path> (points elsewhere; reinstall to update). That is what a stale CLI looks like after an app update.
  • Rerunning either install script upgrades in place.

Fuller diagnostics

jotura doctor reports the executable path, whether its directory is on your PATH, the resolved vault, sync state, share health, document conversion health, and semantic search prerequisites:

jotura doctor

Doctor always exits 0, even when a check reports fail, so scripts must parse the statuses rather than test the exit code. Ask for JSON to do that:

jotura doctor --json

The full check list is in watching and diagnostics.

How the CLI picks a vault

Almost every command resolves a vault before it does anything else. The resolution order is fixed:

Order Source Notes
1 --vault <path> The global flag. It wins over everything else, for that one invocation only.
2 $JOTURA_VAULT An environment variable, useful for a shell session or a service that always works in one vault.
3 The desktop app’s last-opened vault Read from the lastVaultPath key in the desktop app’s settings.json. On a machine that also runs the app, this usually means the CLI needs no configuration.

Whatever the source, the path is canonicalized: symlinks are resolved and the result is made absolute, so it matches what the desktop app stores. On Windows the canonical form is the extended-length one, so commands report paths beginning with \\?\C:\....

If nothing resolves, the path is inaccessible, or the path is not a directory, the command exits 6 with a NoVault error on stderr.

jotura --vault "C:/Users/you/Documents/my-vault" status
export JOTURA_VAULT="$HOME/Documents/my-vault"
jotura status

The desktop settings file lives in the standard config location for each platform:

Platform Settings path
Windows %APPDATA%\jotura\settings.json
macOS ~/Library/Application Support/jotura/settings.json
Linux ~/.config/jotura/settings.json

Reading that file is best-effort at every step, which can hide a problem. An unreadable file, invalid JSON, or a missing lastVaultPath key all produce the same result as having no settings file at all. The command then exits 6 saying no vault was specified, which points you at --vault and $JOTURA_VAULT and gives no hint that the file was found but unusable. If source 3 stops working for no apparent reason, open the settings file and check that it parses.

Commands that need no vault

Two commands are handled before vault resolution runs, so they work on a machine with no vault configured and can never exit 6: completion and the hidden path completer. doctor also never exits 6. It resolves the vault itself and reports a failure as a check result instead of an error.

Global flags

Three flags are declared globally, so clap accepts them at any position and they appear in the options block of every subcommand’s help. jotura --json read notes/a.md and jotura read notes/a.md --json are the same command. Two more flags are worth listing here even though they are not global.

Flag Type Default What it does
--vault <VAULT> path none Global. Overrides vault selection for this invocation, ahead of $JOTURA_VAULT and the desktop’s last-opened vault. Honored by every command, including doctor.
--json boolean off Global. Asks for structured JSON on stdout. Errors are JSON on stderr regardless of this flag. See the next section for which commands branch on it.
-v, --verbose boolean off Global. Logs progress to stderr. In practice this is one line, vault: <resolved path>, emitted after vault resolution. The short -v is taken globally, which is why grep has no invert-match flag.
-h, --help boolean none Per-command, the clap default. Prints help for the command or subcommand you attached it to.
-V, --version boolean none Top level only. jotura read --version is rejected as an unrecognized argument.

Which commands honor --json

Roughly half the commands emit JSON whether or not you ask, because every mutating command already speaks JSON, and this catches people out more than anything else on the surface. Each command either branches on --json, always emits JSON, or ignores the flag, as the table below shows.

Command --json behavior
backlinks Branches on --json
batch Ignores --json, always pretty JSON
clip Branches on --json
context Branches on --json
conventions Branches on --json
create Always JSON
delete Always JSON
doctor Branches on --json
edit Always JSON
frontmatter delete Always JSON
frontmatter get Branches on --json
frontmatter set Always JSON
grep Branches on --json
import Always JSON
links Branches on --json
ls Branches on --json
ls-documents Branches on --json
memory doctor Branches on --json
memory list Branches on --json
memory log Always JSON
memory recall Branches on --json
memory resolve Always JSON
memory supersede Always JSON
quick-open Branches on --json
read Branches on --json
regenerate-md-store Always JSON
rename Always JSON
search Branches on --json
search-documents Branches on --json
shares list Branches on --json
status Always JSON
sync drop-path Branches on --json
sync login Always JSON
sync logout Always JSON
sync status Branches on --json
tag add Always JSON
tag list Branches on --json
tag remove Always JSON
tags Branches on --json
tasks Branches on --json
templates create Always JSON
templates delete Always JSON
templates list Branches on --json
templates show Branches on --json
today --read Branches on --json
today (path and append forms) Always JSON
trash <path> Always JSON
trash empty Always JSON
trash list Branches on --json
trash purge Always JSON
trash restore Always JSON
vault info Always JSON
watch Ignores --json, always compact newline-delimited JSON
write Always JSON

watch emits newline-delimited JSON rather than one pretty document, so a parser that expects a single object will choke on its output.

Every error the CLI itself raises is a single-line JSON object on stderr, in every mode, with a stable code field. Argument-parsing errors are the exception: those come from clap and are plain text, as described under exit codes below. The envelope and its per-code extra fields are documented in exit codes and JSON output.

Environment variables

These are the variables the jotura binary itself reads. The install scripts read three of their own, documented in the script headers: JOTURA_INSTALL_DRYRUN and JOTURA_MANIFEST_URL exist for continuous integration, and DO_NOT_TRACK=1 skips the one anonymous install count a successful install sends to jotura.io.

Variable Purpose
JOTURA_VAULT Default vault path, second in the resolution order above.
JOTURA_SESSION_DIR Overrides the sync key cache directory, which defaults to <config>/jotura/sessions/ (%LOCALAPPDATA%\jotura\sessions\ on Windows). It exists for test isolation. Leave it unset in normal use.
JOTURA_SECRET_STORE Windows only. plain keeps the sync key cache, auth.json and openai.json as plaintext files in %APPDATA%\jotura instead of DPAPI-encrypted files in %LOCALAPPDATA%\jotura, for a machine where an SSH session and the desktop must share them. Set it for both.
JOTURA_MODEL_DIR Overrides the local embedding model directory used by semantic search. An empty value falls through to the default.
OPENAI_API_KEY The key used to embed queries when the vault’s semantic index was built with OpenAI embeddings. Takes precedence over the key the desktop app saves as openai.json in <config>/jotura/ (%LOCALAPPDATA%\jotura\ on Windows).
ORT_DYLIB_PATH macOS only. An explicit path to libonnxruntime.dylib for a standalone build. The bundled CLI resolves the runtime relative to its own executable and sets this itself.
JOTURA_DISABLE_SANDBOX Runs the document converter without a sandbox. doctor surfaces it as a warning.
JOTURA_ALLOW_UNSANDBOXED_CONVERSION The same effect under a different name, and likewise surfaced by doctor as a warning.
JOTURA_CONFIG_DIR Overrides the config directory the CLI reads the desktop settings file from, and the folder it reads openai.json from. It is a test seam, because the platform API ignores HOME and XDG_CONFIG_HOME on Windows. Leave it unset in normal use.
JOTURA_HOME_DIR Overrides the home directory the CLI reads, for the same testing reason. Leave it unset in normal use.

Shell completion

jotura completion <shell> prints a completion script to stdout for one of five shells: bash, elvish, fish, powershell, and zsh. Anything else is a usage error. The script is generated under the command name jotura.

Where you save that output is a matter of your shell’s conventions. Common choices are below.

For bash:

jotura completion bash > ~/.local/share/bash-completion/completions/jotura

For zsh, with ~/.zfunc added to your fpath:

jotura completion zsh > ~/.zfunc/_jotura

For fish:

jotura completion fish > ~/.config/fish/completions/jotura.fish

For elvish:

jotura completion elvish > ~/.config/elvish/lib/jotura.elv

For PowerShell, add this line to your $PROFILE:

jotura completion powershell | Out-String | Invoke-Expression

The generated script completes commands, subcommands, and flags. Note paths are a separate matter. The CLI carries a hidden helper, jotura __complete-paths [PREFIX], that prints one vault-relative path per line for every synced file starting with the prefix. It exists for completion scripts that want to complete note paths. It always exits 0 and never reports an error, even with no vault selected or a failed walk, so a broken completion never surfaces in your shell.

Exit codes at a glance

Every command returns one of these. They form the public contract that lets agent scripts branch on failure without parsing prose.

Code Symbol Meaning
0 Success.
1 Error Generic error, including unclassified input and output failures.
2 HashConflict An --if-hash precondition did not match, or a compare-and-swap write lost the race. In a batch the same code covers one or more entries failing preflight, and the error carries a conflicts array rather than a single diff.
3 NotFound A file was missing, a --replace needle matched nothing, or sync drop-path was given a path with no synced row.
4 Ambiguous A --replace needle matched more than once and neither --all nor --nth was given.
5 OutOfRange A line number, line range, or --nth value was out of bounds.
6 NoVault No vault resolved, the path was inaccessible, or it was not a directory.
8 PermissionDenied A filesystem permission error, or a path that resolves outside the vault.
9 InvalidArgs A bad flag combination or an invalid value, including a wrong sync password or an invalid recovery phrase.
11 MultiEditOpFailed One operation in an edit --apply or batch sequence failed.
12 SyncNotEnabled sync login, sync logout, or sync drop-path ran against a vault with no sync configured. sync status never exits this way: it reports enabled: false instead.
13 SemanticUnavailable Semantic or smart search ran without the desktop app’s vector index in place, or without a usable OpenAI API key for an index built with OpenAI embeddings.
14 TargetMissing An --if-hash write found its target deleted or moved since the read. The file is deliberately not recreated.
15 ReadOnlyShare The target path is inside a view-only share mount.

Codes 7, 10 and 16 are retired, and the numbers will not be reused. Codes 7 and 10 belonged to the encrypted-vault era, when vaults could be locked. Code 16 belonged to the agent config sync that Jotura no longer ships.

Clap’s own usage errors also exit 2, which collides with HashConflict. A missing required argument, an unknown flag, or an invalid enum value exits 2 with human-readable text on stderr instead of the JSON error envelope. A caller that sees exit 2 should check whether stderr parses as JSON before concluding it hit a hash conflict.

The full per-code error payloads, including the fields each one carries, are in exit codes and JSON output.

The only credential step is sync

Nothing about local reading, writing, or searching needs a login. The one exception is optional cloud sync, whose key cache is managed by jotura sync login and jotura sync logout, and read by jotura sync status. The desktop app shares that same cache, so signing in from either surface resumes the other.

jotura sync status

Sync itself is a paid subscription, priced on the pricing page. The app and the CLI are free. Enabling sync, setting or rotating the password, and restoring a vault all happen in the desktop app. See sync and shares for what the CLI does and does not do.

Where to go next