Skip to content

CLI Reference

This page is a user reference for commands and options. The stable machine interface is defined only by the CLI and output contract; synchronization behavior is defined by the synchronization contract.

Global conventions:

  • --json: deterministic machine-readable envelope on stdout; logs and diagnostics go to stderr. No ANSI codes in JSON. Keys are sorted.
  • --verbose / --quiet control stderr logging; --log-file PATH adds a debug log file. The token is redacted from all channels.
  • Connection options (where relevant): --base-url URL, --port N, --token-file PATH, --timeout SECONDS, --allow-remote-api. Without any of them (and without env/workspace overrides) the built-in default http://127.0.0.1:41184 is used when it answers /ping, with a fallback scan of ports 41184-41194. Only the token must be configured.
  • The Joplin token comes from exactly one source: --token-file PATH or the JOPLIN_TOKEN environment variable. Setting both is an error that names both sources; an empty JOPLIN_TOKEN counts as unset. The token file must be private: one line in a regular file (not a symlink) owned by you, with mode 0600 on Linux, and on Windows owned by you with no access for other accounts, for example after icacls FILE /inheritance:r /grant:r "%USERNAME%:(R)". Files that others can read or change are rejected without echoing their content.
  • Workspace commands take --root PATH (default: current directory).
  • --help prints the parser reference; top-level --version prints the package version without the richer version command envelope.

JSON envelope

For example, a successful push --json response begins with the common fields owned by CLI-001:

{
  "schema_version": 1,
  "command": "push",
  "success": true,
  "exit_code": 0,
  "code": "OK",
  "tool_version": "1.7.0",
  "workspace": "/abs/path/notes"
}

Command-specific fields include summary, items, execution, planned_operations, checks, and conflicts. Read exit_code and code together instead of parsing human-readable diagnostics.

Exit codes

The complete stable mapping and evidence are in CLI-002. Clients can discover the same public surface with capabilities --json.

Commands

version, capabilities, update-check

  • version --json → tool, python, protocol/state/output schema versions, distribution kind (standalone / wheel / zipapp / source).
  • capabilities --json → command list, feature flags, exit-code table.
  • update-check --json [--include-prerelease] [--offline] → queries the GitHub Releases API. Exit 0 current, 8 outdated (code: VERSION_OUTDATED, with an exact update_command), 4 when the check cannot be completed (code: UPDATE_CHECK_FAILED), 0 with code: UPDATE_CHECK_SKIPPED for --offline. It never self-updates. Use --include-prerelease only when preview releases are relevant.

init --root PATH [--mode remote-first|local-first]

Creates .joplin-sync/ (state DB, config, journal/backup/conflict dirs) and a .gitignore. remote-first (default) refuses to run when unmanaged *.md files already exist (exit 7, listing them). local-first adopts them: files without a Joplin id are pushed as new notes, and the first real push requires a preceding push --dry-run. --mode selects the initialization policy.

doctor --root PATH [--offline]

Checks python version, workspace integrity, state DB, incomplete runs, open conflicts, invalid files, lock availability, Joplin ping + token. Exit code = severity of the first problem (3/6/2/4/5), 0 when healthy.

status --root PATH

Offline: local files vs base snapshot only (remote_state: "unknown"). Reports tracked counts, local changes, open conflicts, incomplete runs.

pull / push / sync --root PATH [--dry-run] [--propagate-deletes]

Scan → classify → plan → journal → apply (guard, apply, verify, commit base per operation). --dry-run prints planned_operations and exits 1 when work is pending (0 when clean, 2 when conflicts exist), mutating nothing. Deletions are only reported unless --propagate-deletes.

diff --root PATH [modes]

Never mutates. Modes: --summary (default), --name-status, --unified, --three-way, --against remote|base, --note ID_OR_PATH, --offline. Exit code is always 0 unless --exit-code is passed (then 1 = differences, 2 = conflicts). Unified diff labels: joplin/<note-id>, local/<relative-path>, base/<note-id>.

recover --root PATH

Settles incomplete journals: verifies which operations completed (base snapshots are committed before an op is marked applied, so current state is the witness), marks the rest "not applied; rerun", removes stray temp files, and unblocks the workspace.

conflicts list | show ID | resolve ID MODE | discard ID

See CONFLICTS.md.

note set-title PATH TITLE, note set-tags PATH [TAG...], note validate PATH

Safe header editing (atomic rewrite; adds a header to plain files) and validation (exit 3 for a malformed header).

resources pull --root PATH

Downloads every :/resource-id referenced by managed notes into .joplin-sync/resources/<id>[.ext]. Markdown links are never rewritten.

mcp stdio [--token-file PATH | --token TOKEN] [--port PORT]

Runs a local MCP server over stdin/stdout for an IDE or agent that launches the executable directly. Joplin Desktop must already be running locally with Web Clipper enabled. --port PORT selects its Data API port on 127.0.0.1 (default 41184). No network MCP listener or Markdown workspace is created.

The Joplin token comes from exactly one of two paths:

  • the command line: --token-file PATH, the recommended form, or the compatibility --token TOKEN; the two options are mutually exclusive;
  • the JOPLIN_TOKEN environment variable, for launchers that export it.

A command-line option together with a non-empty JOPLIN_TOKEN is a configuration error that names both sources; neither silently wins, and the check runs before the file is read or Joplin is contacted. An empty or whitespace-only JOPLIN_TOKEN counts as unset. With no source the command fails and names both paths. These errors exit with code 4 and write only to stderr, so the protocol stream on stdout stays clean.

--token-file PATH follows the same private-file rules as every other command: a regular file, not a symlink, holding one line with the token, mode 0600 on Linux or restricted to your account on Windows. Oversized, empty, multi-line, or non-ASCII files are rejected without echoing their content. Create it once outside synchronized folders:

install -d -m 0700 ~/.config/joplin-md-sync
(umask 077; read -rs -p 'Joplin token: ' token &&
  printf '%s\n' "$token" > ~/.config/joplin-md-sync/token)

--token TOKEN remains for existing IDE configurations only. IDE configuration persists command arguments, other processes of the same user can list them, and some editors forward the MCP configuration to agents on their command lines, so prefer the token file.

This mode does not expose /mcp, GPT Actions, /healthz, or /readyz and does not accept --auth-token-file, --gpt-actions, or --gpt-actions-token-file. Those bearer credentials protect HTTP interfaces that do not exist in stdio mode; only the Joplin token is used.

The optional --timeout SECONDS, --retry-timeout SECONDS, and --retry-delay SECONDS settings have the same call behavior as mcp serve. The process reads one JSON-RPC message per stdin line, writes only JSON-RPC to stdout, and exits when the client closes stdin. --verbose, --quiet, and --log-file PATH affect diagnostics on stderr or in the selected log file.

mcp serve [connection and server options]

Runs a foreground MCP Streamable HTTP server at http://127.0.0.1:8765/mcp by default. It exposes note, notebook, tag, and binary-resource CRUD, trash/restore where Joplin supports it, Markdown/HTML content, attachments, relationship traversal, and full-text search. No workspace is required.

This remains the network listener mode. Without the separate mcp stdio subcommand, the HTTP listener and its existing MCP/Actions options behave as before.

For note creation, pass an existing parent_id or a notebook_title to find/create a root notebook. With neither, MCP Notes is found or created. Explicit create tools reject an occupied natural identity; see Create conflicts for the comparison keys and recovery workflow.

Joplin connection options are the normal --base-url, --port, --token-file, --timeout, and --allow-remote-api. Server options:

  • --host HOST, --mcp-port PORT, --mcp-path PATH
  • --retry-timeout SECONDS, --retry-delay SECONDS, --discovery-timeout SECONDS
  • --auth-token-file PATH to enable MCP pre-shared bearer authorization; the protected file must contain a URL-safe Base64 token encoding at least 32 bytes generated by a cryptographically secure random generator
  • repeatable --allowed-origin ORIGIN
  • --allow-remote-mcp for an explicit non-loopback bind; this also requires --auth-token-file
  • --gpt-actions to add authenticated /api/gpt/v1/tools/* routes to the same listener
  • --gpt-actions-token-file PATH (required with --gpt-actions)
  • --gpt-actions-max-request-bytes N, --gpt-actions-max-response-chars N, --gpt-actions-max-concurrency N, and --gpt-actions-rate-limit REQUESTS_PER_MINUTE

The command intentionally stays in the foreground. Full protocol behavior, security guidance, MCP client configuration, and service-manager examples are split by purpose between MCP API and Joplin API Service.

Actions-only options are rejected unless --gpt-actions is present. The Actions token file is required, re-read on each request, protected like every token file (POSIX mode or Windows ACL), and must differ from the Joplin and MCP credentials.

gpt-actions export-openapi --server-url URL --output PATH

Generates deterministic OpenAPI 3.1 JSON from the shared tool registry without contacting Joplin. --server-url must receive an HTTPS origin on port 443 with no path, query, fragment, or credentials. --output selects the destination JSON file. The result reports operation_count, registry_hash, server_url, and output.

The repository does not store a generated contract. Export it with the real public hostname immediately before importing or updating a Custom GPT. See ChatGPT Actions end-to-end setup.