Jotura

Docs / The CLI / Install and setup

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.

PlatformWhere the binary landsHow it reaches your PATH
macOS (.dmg or .app)Jotura.app/Contents/MacOS/joturaOpen 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.exeThe 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/joturaAlready 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. Use the Settings card instead. 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 six 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. Install the Jotura agent skill for any AI coding agents found on the machine.
  6. Launch the app.

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.

PlatformApp locationCLI locationPrivileges needed
macOS/Applications/Jotura.app, with the quarantine flag clearedSymlink at /usr/local/bin/joturasudo 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 entryCopied to ~/.local/bin/joturaNone
Linux, --debSystem package, launched as jotura-desktop/usr/bin/joturasudo, and the install fails without it
WindowsInstall folder chosen by the MSIjotura.exe in that folder, on the system PATHA 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 reports that the install succeeded and Windows wants a reboot to finish. That is a success, not a failure.

Installer flags

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

FlagEffect
--no-launchDo not launch the app when the install finishes.
--skills <mode>Which agent skills to install. Accepts all, claude, codex, gemini, copilot, or none. The default detects agents by looking for ~/.claude, ~/.codex, ~/.gemini, and ~/.copilot.
--debLinux only. Install the .deb system package instead of the AppImage.
-h, --helpPrint the script’s help and exit.

For example, to install without launching the app and without touching any agent config:

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

The PowerShell script takes the same choices as parameters, but only when you download the file and run it rather than piping it into iex:

ParameterEffect
-NoLaunchDo not launch the app when the install finishes.
-Skills <mode>One of detect, all, claude, codex, gemini, copilot, or none. The default is detect.

Skill installation is a convenience of the installer, not a requirement. You can wire agents up at any time with the skill and agents commands, which are covered in the agent surface.

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.7.0. That version comes from the binary itself, so it tells you which build you are actually 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 agents 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:

OrderSourceNotes
1--vault <path>The global flag. It wins over everything else, for that one invocation only.
2$JOTURA_VAULTAn environment variable, useful for a shell session or a service that always works in one vault.
3The desktop app’s last-opened vaultRead from the lastVaultPath key in the desktop app’s settings.json. This is why the CLI usually just works on a machine that also runs the app.

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:

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

One failure mode to know about: reading that file is best-effort at every step. 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

A few commands are handled before vault resolution runs, so they work on a machine with no vault configured and can never exit 6: completion, hook install, skill install, skill list, skill show, 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.

FlagTypeDefaultWhat it does
--vault <VAULT>pathnoneGlobal. Overrides vault selection for this invocation, ahead of $JOTURA_VAULT and the desktop’s last-opened vault. Honored by every command, including doctor.
--jsonbooleanoffGlobal. Asks for structured JSON on stdout. Errors are JSON on stderr regardless of this flag. See the next section for which commands actually branch on it.
-v, --verbosebooleanoffGlobal. 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, --helpbooleannonePer-command, the clap default. Prints help for the command or subcommand you attached it to.
-V, --versionbooleannoneTop level only. jotura read --version is an unrecognized-argument error, not a version print.

Which commands honor --json

This is the most surprising part of the surface, so it is worth stating plainly. Roughly half the commands emit JSON whether or not you ask, because every mutating command already speaks JSON. There are three behaviors, and the table below gives the behavior for every command.

Command--json behavior
agents statusBranches on --json, emitting newline-delimited JSON
agents syncBranches on --json, emitting newline-delimited JSON
backlinksBranches on --json
batchIgnores --json, always pretty JSON
contextBranches on --json
conventionsBranches on --json
createAlways JSON
deleteAlways JSON
doctorBranches on --json
editAlways JSON
frontmatter deleteAlways JSON
frontmatter getBranches on --json
frontmatter setAlways JSON
grepBranches on --json
hook installAlways JSON
importAlways JSON
linksBranches on --json
lsBranches on --json
ls-documentsBranches on --json
memory listBranches on --json
memory logAlways JSON
memory recallBranches on --json
memory resolveAlways JSON
memory supersedeAlways JSON
quick-openBranches on --json
readBranches on --json
regenerate-md-storeAlways JSON
renameAlways JSON
searchBranches on --json
search-documentsBranches on --json
shares listBranches on --json
skill installIgnores --json, always newline-delimited JSON
skill listBranches on --json
skill showIgnores --json, always the raw skill file
statusAlways JSON
sync drop-pathBranches on --json
sync loginAlways JSON
sync logoutAlways JSON
sync statusBranches on --json
tag addAlways JSON
tag listBranches on --json
tag removeAlways JSON
templates createAlways JSON
templates deleteAlways JSON
templates listBranches on --json
templates showBranches on --json
today --readBranches on --json
today (path and append forms)Always JSON
trash <path>Always JSON
trash emptyAlways JSON
trash listBranches on --json
trash purgeAlways JSON
trash restoreAlways JSON
vault infoAlways JSON
watchIgnores --json, always compact newline-delimited JSON
writeAlways JSON

Three commands emit newline-delimited JSON rather than one pretty document: agents status, agents sync, and skill install. So does watch. That matters if you pipe output into a parser expecting a single object.

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 two the install scripts read, JOTURA_INSTALL_DRYRUN and JOTURA_MANIFEST_URL, exist for continuous integration and are documented in the script headers.

VariablePurpose
JOTURA_VAULTDefault vault path, second in the resolution order above.
JOTURA_SESSION_DIROverrides the sync key cache directory, which defaults to <config>/jotura/sessions/. It exists for test isolation. Leave it unset in normal use.
JOTURA_MODEL_DIROverrides the embedding model directory used by semantic search. An empty value falls through to the default.
ORT_DYLIB_PATHmacOS 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_SANDBOXRuns the document converter without a sandbox. doctor surfaces it as a warning.
JOTURA_ALLOW_UNSANDBOXED_CONVERSIONThe same effect under a different name, and likewise surfaced by doctor as a warning.
JOTURA_CONFIG_DIROverrides the config directory the CLI reads, which is where the desktop settings file and the session cache live. 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_DIROverrides 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 are the public contract, and they are the reason agent scripts can branch on failure without parsing prose.

CodeSymbolMeaning
0Success.
1ErrorGeneric error, including unclassified input and output failures.
2HashConflictAn --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.
3NotFoundA file was missing, a --replace needle matched nothing, or sync drop-path was given a path with no synced row.
4AmbiguousA --replace needle matched more than once and neither --all nor --nth was given.
5OutOfRangeA line number, line range, or --nth value was out of bounds.
6NoVaultNo vault resolved, the path was inaccessible, or it was not a directory.
8PermissionDeniedA filesystem permission error, or a path that resolves outside the vault.
9InvalidArgsA bad flag combination or an invalid value, including a wrong sync password or an invalid recovery phrase.
11MultiEditOpFailedOne operation in an edit --apply or batch sequence failed.
12SyncNotEnabledsync 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.
13SemanticUnavailableSemantic or smart search ran without the desktop app’s vector index in place.
14TargetMissingAn --if-hash write found its target deleted or moved since the read. The file is deliberately not recreated.
15ReadOnlyShareThe target path is inside a view-only share mount.
16AgentConflictagents sync found files changed on both the vault and the system side.

Codes 7 and 10 are retired. They belonged to the encrypted-vault era, when vaults could be locked, and the numbers will not be reused.

One collision to guard against: clap’s own usage errors also exit 2. A missing required argument, an unknown flag, or an invalid enum value exits 2 with human-readable text on stderr, not 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