Command line

Use OneNote from a terminal

onenotesystem is the official command-line client. It sends the same requests the Apple Shortcuts send, to the same deployment, so a page created from a Linux server and a page created from your iPhone are identical. It also drives Microsoft To Do. It is built for the machines OneNote will not run on.

Why a terminal client

Microsoft does not ship OneNote for Linux, and many workplaces will not let you install it at all. The web app covers reading, but it is a poor fit for the thing people actually want from a shell: capturing what just happened without leaving the shell.

Linux desktops

The one supported way to put a page in your own OneNote notebook from Ubuntu, Fedora, Arch, or anything else, without a browser.

Servers over SSH

Pipe a log, a diff, or a failing test into a OneNote page from a machine that has no graphical session at all.

Locked-down work machines

If you can install a Node package, you can capture notes. There is nothing to install with administrator rights and no browser extension.

Scripts and cron

Stable exit codes and --json output make it safe to call from automation that has to react when something fails.

Install

The client is published to npm as onenotesystem ↗, and its source is at onenote-terminal ↗. It needs Node.js 18.17 or newer and has no other dependencies.

npm install -g onenotesystem

That installs two commands: onenotesystem and the shorter alias ons. To try it without installing anything, run npx onenotesystem --help.

Getting help

Every command documents itself, so you should rarely need this page once it is installed. --help and -h work at the top level and on each command, and help <command> does the same thing.

onenotesystem --help              # commands, configuration, exit codes
onenotesystem capture --help      # every flag capture accepts, with examples
onenotesystem help append         # the same, spelled the other way

Aliases resolve too, so onenotesystem new -h shows the capture help.

The client is not a OneNote account. It talks to your OneNote System deployment, which holds your Microsoft connection. If you have not deployed one yet, start with the guided setup.

Configure

You need your deployment address and an API key from Setup Step 5 — the same key a Shortcut would use. One key can be shared by both, though a separate key per device is easier to revoke.

$ onenotesystem configure
OneNote System deployment URL: https://my-onenote-system.vercel.app
API key (input hidden):
Checking the deployment...
Reached onenote-system.
Saved configuration to /home/you/.config/onenotesystem/config.json

The key is saved to a file only your user account can read: ~/.config/onenotesystem/config.json on Linux and macOS, or %APPDATA%\onenotesystem\config.json on Windows. It is never printed back to the terminal.

Configuring without prompts

Pass the values as flags when you are setting up a server or a container:

onenotesystem configure --url https://my-onenote-system.vercel.app --api-key "$KEY" --default-page "Quick Inbox"

Or skip the file entirely. Environment variables take precedence over it, which is what you want in CI:

VariablePurpose
ONENOTE_URLYour deployment address, with no slash at the end
ONENOTE_API_KEYAn API key from Setup Step 5
ONENOTE_DEFAULT_PAGEPage title append uses when you do not name one
ONENOTE_TIMEOUT_MSRequest timeout, default 15000
ONENOTE_CONFIG_DIROverride where the config file lives

Check that it works

doctor tests the deployment, its database, and your API key separately, so a failure tells you which one is wrong.

$ onenotesystem doctor
Deployment URL: https://my-onenote-system.vercel.app  (from config file)
API key:        set (from config file)
Default page:   Quick Inbox  (from config file)
Service:        onenote-system
Database:       reachable
Key:            accepted

Create a page

capture creates a new page in the OneNote section you chose during setup. It calls POST /api/capture — the same endpoint as the Capture to OneNote Shortcut.

# A page with just a title
onenotesystem capture "Standup notes"

# A page with a body
onenotesystem capture "Standup notes" --content "Shipped the CLI"

# A page from a file, with a source link
onenotesystem capture "Article" --file notes.md --url https://example.com/article

# A page from whatever another command printed
git log -1 --stat | onenotesystem capture "Today's commit" --stdin
FlagMeaning
--title <text>Title, if you would rather not use positional words
--content <text>Page body
--file <path>Read the body from a file
--stdinRead the body from piped input
--url <link>Record a source link under the body
--jsonPrint the deployment's JSON response instead of a summary

Pages carry a title, plain text, and an optional source link — the same small, reliable format the Shortcuts use. Line breaks are preserved. Markdown is not rendered; it arrives as literal text. Content is limited to 100,000 characters and titles to 200, both checked before anything is uploaded.

Append to a page

append adds text to a page that already exists — a running inbox, a daily log, a project page. It calls POST /api/append.

# Add to a page by its exact title
onenotesystem append "Ask about the Q3 budget" --page-title "Quick Inbox"

# Add to a page by ID, from any section
onenotesystem append "Deploy finished" --page-id "1-abc123!..."

# Add whatever another command printed
dmesg | tail -20 | onenotesystem append --stdin --page-title "Server log"

# Set a default page once, then leave the flag off
onenotesystem configure --default-page "Quick Inbox"
onenotesystem append "A thought"

--page-title must match a page title exactly, and that page must be in your configured default section. If two pages share the title the command stops and asks for --page-id, because quietly appending to the wrong one would be worse than failing. A page ID can reach any section the connected Microsoft account can see.

Microsoft To Do

todo creates and completes Microsoft To Do tasks through the same deployment and the same API key. Calls /api/todo.

# Add a task to your default To Do list
onenotesystem todo add "Renew the domain" --due +7d

# A specific list, with a note and a reminder
onenotesystem todo add "Call the bank" --list Errands --due tomorrow --note "Ask about the fee"

# See what is open, then close one out
onenotesystem todo list
onenotesystem todo done AAMkAG...
FlagMeaning
--list <name>Which To Do list to use; defaults to your default list
--due <when>2026-09-15, today, tomorrow, +3d, +2w, or 2026-09-15T14:30
--reminder <when>Same formats; also switches the reminder on
--note <text>A longer note on the task
--allOn todo list, include completed tasks
--top <n>On todo list, how many to show (default 25, max 100)

Dates are sent with your computer's time zone, so a bare date stays the day you meant rather than shifting for anyone west of UTC. todo list prints each task's ID underneath it, which is what todo done takes.

To Do needs the Tasks.ReadWrite permission on your Microsoft app registration. If you added it after connecting, reconnect Microsoft in setup — a permission added later does not upgrade a connection that was already approved. OneNote keeps working throughout, and the client tells you plainly when this is the problem.

Scripting

Progress messages go to stderr and --json goes to stdout alone, so onenotesystem capture … --json | jq always works.

#!/usr/bin/env bash
# Log a failed nightly build to OneNote without opening a browser.
if ! make nightly > build.log 2>&1; then
  onenotesystem capture "Nightly build failed $(date -I)" --file build.log
fi

Every command returns a stable exit code, so a script can tell an expired key apart from a dropped connection:

CodeMeaning
0Success
1Usage error — bad flags, missing input, failed local validation
2Unauthorized — the deployment rejected the API key
3Not found — no page matched the title or ID
4Network — DNS, TLS, timeout, or connection refused
5A deployment error the client cannot classify further
6Not configured — no deployment URL or API key
7Conflict — no default section, or more than one page has that title
if ! onenotesystem append "$LINE" --page-title "Log"; then
  case $? in
    2) echo "Key expired; run onenotesystem configure" ;;
    4) echo "Offline; queueing locally" ;;
  esac
fi

Security

Your API key is sent only to the deployment address you configured, as an Authorization: Bearer header. It is never printed, logged, or included in an error message — including the unauthorized one. The config file is written with owner-only permissions.

Deployment addresses must use HTTPS. Plain http:// is accepted only for localhost and 127.0.0.1, so a typo cannot quietly send your key over an unencrypted connection.

Your note content passes through your own deployment to Microsoft Graph and nowhere else. The client has no telemetry and no runtime dependencies.

On a shared machine, prefer an environment variable to the config file, and create a key you can revoke for that machine alone. Anyone who can read the file can write to your OneNote section.

Terminal troubleshooting

Exit code 6, “not configured”

No deployment URL or API key was found. Run onenotesystem configure, or set ONENOTE_URL and ONENOTE_API_KEY.

Exit code 2, “unauthorized”

The key was rejected. Keys are shown only once at creation; if the original was lost, create a new one in Setup Step 5 and run configure again.

Exit code 7, “no default OneNote section”

Return to Setup Step 4, load your notebooks, and choose the section that should receive new pages.

Exit code 3, “no page titled …”

Titles must match exactly, including capitalisation, and the page must be in your default section. Use --page-id to reach a page in another section.

Exit code 4, “could not reach”

Run onenotesystem doctor. If it also fails, open your deployment address in a browser before changing anything about the client.

command not found after install

npm's global bin directory is not on your PATH. Run npm config get prefix and add that directory's bin to your shell profile.

For deployment and Microsoft errors, continue with the full troubleshooting guide →