Maisnie

User guide · Software preview

The command line

Everything day to day goes through one command, maisnie. This page documents every subcommand, every flag, and what each exit code means. (The same install also provides the command under its older name, majordomo, Maisnie’s internal codename, so anything already scripted against it keeps working. Both run exactly the same program.)

maisnie [--data-dir DATA_DIR] {init,up,status,stop,start-at-login,doctor,unclaim,unlock,relocate,storage,vault,backup,restore,run,pause,resume,secrets,remote,card} ...

--data-dir is a global option that comes before the subcommand and overrides $MAISNIE_HOME (and the older $MAJORDOMO_HOME, still honoured when $MAISNIE_HOME isn’t set) and the per-OS default data directory for that one invocation. See install for the default locations.

maisnie --version

maisnie --version

Prints the product name and the installed version (Maisnie 0.5.0, for example) and exits 0: no subcommand, no data directory needed. Useful on its own, and worth including whenever you report a problem, since it names exactly which build you’re running.

maisnie init

maisnie init [--port PORT] [--force]

Writes the configuration document to <data>/config/majordomo.json, with every path already filled in for the chosen data directory. Refuses to overwrite an existing document unless you pass --force (this only rewrites the configuration document itself: it never touches your vault or any notes).

  • --port PORT: the front port (default 8080). The two ports behind it follow automatically at PORT + 1 and PORT + 2.
  • --force: overwrite an existing configuration document.

maisnie up

maisnie up [--lan] [--no-browser]

Starts the box in the foreground: the gatekeeper, the setup surface, and the Home surface, each as its own process, restarted with increasing backoff if one of them crashes. If any one of them keeps crashing too many times too fast, up gives it up: logs it, stops every child (not just the one that failed) and exits 1, rather than leaving the box half-running. Prints the URL to open. Ctrl+C prints “Shutting down…” and stops every child process cleanly, releasing the instance lock. On Windows, Ctrl+Break does the identical clean shutdown: Python has no built-in handling for it the way it does for Ctrl+C, so without up’s own handler it would kill the process outright and leave the gatekeeper and Desk running as orphans holding their ports; up catches it and shuts down the same way Ctrl+C does. A second up against the same data directory refuses, because the first one already holds that lock.

  • --lan: bind the front port on all network interfaces instead of loopback-only. Refused until the box has been claimed. See first boot.
  • --no-browser: do not open the claim page in your browser by itself. Without it, up opens the page in your default browser when the box has not been claimed yet and up is running in a terminal you can type in (not when its output goes to a file or another program). If the browser cannot be opened, up carries on and the printed address still works.

maisnie status

maisnie status [--json]

Reports whether an instance is running (by checking the same lock up holds, never by guessing from a process id), whether the box has been claimed, each surface’s reachability, and every configured connection’s status. Every line reads as one plain sentence, never a raw connection error. The first line is the installed version. A stopped box reports, for example:

Version: 0.22.0
Running: no
Claimed: unknown
Front door: stopped
Setup: stopped
Home: stopped

The claim answer only works while the box is running: it comes from asking the live gatekeeper, so a stopped box (exactly the state you’d run status in before unclaim) reports Claimed: unknown, not a real yes or no: the line above it already says the box isn’t running, so this isn’t a contradiction to chase. A connection’s own status, once the box is running, is the Desk’s last saved test result, not a fresh check status runs itself; while the box is stopped, each connection line says as much (“as of the last test, not checked just now”) rather than implying a live answer it can’t back up. The last line says whether start at sign-in is on (Starts when you sign in: yes or no; --json carries it as start_at_login). --json prints the same information as one JSON object, for scripting.

maisnie stop

maisnie stop

Stops a running box cleanly, whether you started it with up in a window or it started by itself at sign-in (and so has no window to press Ctrl+C in). It leaves a stop request that the running up notices within a second, then waits (up to about a minute and a half) until the box has shut down every service and let go of its lock, and says so. It signals no process id, so it can never stop anything else. If nothing is running it says so and exits 0. Ctrl+C only works in the window where up was started.

maisnie start-at-login

maisnie start-at-login [--off]

Makes Maisnie start by itself when you sign in to this computer, so it answers at its address after a restart with no terminal open. It starts exactly what maisnie up starts, with the same Python and the same data folder this command was run against. status has a line that says whether it is on. Run it twice and nothing changes; --off removes what it set up, and only that. --off does not stop a box that is running right now: it says so, and maisnie stop stops it.

  • Windows: a small Maisnie.vbs in your Startup folder. It runs the console-less pythonw, hidden, so no window ever appears. Output goes to start-at-login.log in the logs folder.
  • macOS: a Launch Agent (com.maisnie.up.plist in ~/Library/LaunchAgents), loaded with launchctl bootstrap and removed with launchctl bootout. Loading it starts Maisnie right now and at every sign-in. If Maisnie is already running, it is left alone and the agent only takes effect at the next sign-in.
  • Linux: a systemd user service (maisnie.service in ~/.config/systemd/user), switched on with systemctl --user enable and off with disable. It starts when you sign in, not at power-on.

On Windows and Linux it starts at the next sign-in, not right now: if Maisnie is not running yet, start it once with maisnie up. A data folder whose path contains a percent sign cannot be used on Windows (Windows would rewrite it). If you move the data folder, run the command again from the new place.

maisnie doctor

maisnie doctor [--json]

Pre-flight checks: the Python version, whether the data directory is writable, whether the configuration document loads through every component that reads it, whether the chosen ports are free (or already held by this same instance), whether git is on PATH if version history is enabled, whether the folder paths saved in the configuration document still point at this data directory (a copied or moved one fails here, and the line names maisnie relocate), whether your Python has a time zone database, whether your SQLite build supports full-text search, and whether a configured subscription lane’s binary path is set and isn’t pointed at Maisnie’s own model gateway by mistake. A missing time zone database or an advisory-only file-permission note on Windows prints as informational, not a failure. --json prints the same checks as one JSON object.

maisnie unclaim

maisnie unclaim [--yes]

Removes the claim, so the next visitor to reach the box claims it fresh with a new passphrase. This is the recovery path for a forgotten passphrase: there is no “reset my passphrase” flow, on purpose, because there’s no way to prove who’s asking that isn’t itself a security hole. The instance must be stopped first (unclaim refuses while up’s lock is held). Without --yes it does nothing but print what it would do and exit; pass --yes to actually remove the claim: this is not an interactive confirmation prompt, just a required flag.

maisnie unlock

maisnie unlock

Clears the login lockout counter. Use this if you (or someone else) triggered the five-attempts lockout and you don’t want to wait out the cooldown. It does not touch the claim or the passphrase itself.

maisnie relocate

maisnie relocate

Run it after the data directory was copied or moved to a new place. init saves a few absolute folder paths in the configuration document (runtime.data_dir, runtime.state_dir, runtime.log_dir, gatekeeper.state_home and llm.telemetry.dir); a copy still carries the old ones, which maisnie doctor reports. relocate works on the data directory the usual options give it (--data-dir, $MAISNIE_HOME, or the default), prints each old and new path, keeps a fresh copy of the document beside it (majordomo.json.relocate-<date>-<time>.bak), and rewrites only those paths. Nothing else in the document changes, and sealed values are left as they are. On macOS, where the key that opens them is a Keychain item named by the data directory’s path, it first carries that key to the new path and proves every sealed value opens there, even when no saved path reads as stale (a symlink to the same folder is a different Keychain path). If it cannot (the old key is not on this Mac, a value does not open with it, or the new path already holds a key that does not open them all), it changes nothing and says what to do: run maisnie secrets open on the folder the copy came from, copy that folder again, then run relocate and maisnie secrets seal on the new copy. On Windows, Linux and Docker the key is a file in the data directory and moves with it; backup and restore has the table for another computer or account. If every path already points at this data directory it says so and writes nothing, so running it twice is harmless. It refuses, exiting 1, while the box is running (stop maisnie up first).

maisnie storage

maisnie storage [--json]

Shows how much space each folder Maisnie uses takes, and how much is free on the disk it lives on. It lists your vault, the data directory, and the folders the settings file names inside it (working state, logs, the sign-in state and the spend records), plus the folder backups are saved in. Each line gives the full path, the size on disk, the number of files, and the free space on that disk. The data directory’s size includes the folders listed after it. A folder that does not exist says so instead of failing. Links (shortcuts and junctions) are counted as one file and never followed, so a link out of a folder does not add another disk’s size. --json prints the same facts as one JSON object with a folders list. It only reads: it never writes, creates or removes anything. The same facts are on the Storage section of the Settings page.

maisnie vault move

maisnie vault move [--dry-run] NEW_FOLDER

Moves your vault to another folder, for example to a bigger disk. Stop Maisnie first: it refuses, exiting 2, while the box is running. It refuses before copying anything if the new folder is inside the vault or the data directory (or holds either of them), is not empty, or sits on a disk without room for the vault plus a margin. It also refuses if the vault contains shortcuts or junctions (a copy would leave them behind) or if another saved setting or state file names the old vault folder, because a move would leave that pointing at the old copy.

Then it copies every file, including the .git folder when the vault keeps version history, with the same modification times, and checks the copy: every file must be present with the same size and SHA-256. If anything differs it changes nothing else: the settings stay as they were, the old folder is untouched, and it names what differed. Only when the copy is exact does it switch the vault path in the settings, in one atomic write.

The old folder is never deleted. It is kept as a safety copy; run maisnie doctor and start Maisnie to check things work with the new location, and delete the old folder by hand when you are happy. --dry-run runs all the checks and prints the plan (what would be copied, how much room is needed), then stops without copying or changing anything.

maisnie backup

maisnie backup FOLDER

Copies the data directory and the vault into a new folder named maisnie-backup-<date>-<time> inside FOLDER, with a manifest.json listing every file’s size and checksum. Every password and key in the data folder is left out (the place is emptied, so Setup shows it as not entered), along with the key that opens sealed values, the plain-text .bak copies, live sign-in material, logs and any media folder; the vault is copied as it is. It prints file counts, the backup’s path and how many passwords and keys were left out, never a value. If no vault is set up, or its folder is gone, it says so and backs up the data directory only. It refuses, exiting 2, while the box is running (stop maisnie up first), when FOLDER is inside the data directory or the vault, and when the dated folder already exists; it writes nothing in each case. See backup and restore.

maisnie restore

maisnie restore BACKUP [--vault-dir PATH] [--replace]

Puts a backup made by maisnie backup back, into the data directory the usual options give it (--data-dir, $MAISNIE_HOME, or the default). It checks every file against the manifest, and that nothing extra is in the backup, before it writes anything; then it copies the data directory in, fixes the saved folder paths the way relocate does, copies the vault to --vault-dir and points the settings at it. --vault-dir is required when the backup holds a vault, and must be new or empty. It refuses, exiting 2 and writing nothing, while the box is running, when the data directory already holds settings (add --replace to move it aside to a dated folder first), when --vault-dir is not empty, or when the backup fails its check. It ends by telling you to run maisnie doctor and enter each password and key again in Setup.

maisnie run

maisnie run TOOL

Runs every one of TOOL’s jobs once, right now, and exits with the result: 0 on a clean run, and otherwise exactly the connector’s own exit code, passed straight through unchanged (1 for a runtime failure such as a network error, 2 for a configuration problem such as a missing vault or a secret that was never set: the connector reuses the same code an operator error would use here, so a failed run is not always exit 1). TOOL is one of the names in the shipped manifest (ical, imap, feeds in this release; an unrecognized name is refused with the list of what’s actually there, exit 2). Unlike the scheduler’s own tick, this ignores whether TOOL is currently turned off on the Sources step (an explicit run is you asking for it right now, not the scheduler deciding whether it was due) but it still refuses a tool that isn’t installed in this build. See connect your accounts for how often each tool runs on its own.

maisnie pause / maisnie resume

maisnie pause
maisnie resume

pause stops the scheduler from starting any new connector run; a run already under way when you pause finishes normally, never cut off mid-sync. resume lets it start scheduling runs again. Both just write or remove a plain flag file under the data directory, so either works whether or not maisnie up is currently running: pausing ahead of time means the box comes up already paused, and the scheduler notices a pause or resume within moments either way (it re-checks the flag on every tick, not just at startup). Both are idempotent: pausing an already-paused box, or resuming one that was never paused, is the same request twice, not an error.

You do not need the command line for this: Settings > Updates from your sources has a Pause updates / Resume updates button (it sets and clears the very same flag file), and while updates are paused Home shows an “Updates are paused” line with a Resume button (a session from away that can only read sees the line without the button). maisnie status prints a Source updates: line saying paused or running.

maisnie card write / maisnie card check

maisnie card write PATH [--force]
maisnie card check PATH

write saves this computer’s own setup as a setup card at PATH: every choice, and a note in place of every password and key it has saved, never a password or key itself, or anything that looks like one; a plain value that looks like one is left out of the card and counted instead. Refuses to overwrite an existing file unless you pass --force. check reads a card the way importing it would and says whether it can be used, without changing anything, unlike importing it in the Desk, it accepts a card written for a different computer, so it can check one before sending it on. See import a setup card for the owner’s side of this, and write a setup card for the format and what each check refuses.

Exit codes

Code Meaning
0 Success.
1 doctor found a real problem (including a configuration document that fails to load: doctor reports that as a failed check, not a crash), unclaim wasn’t confirmed with --yes, relocate found the box still running or could not carry the sealed key to the new path, up gave up on a service that kept crashing and stopped the whole box (see below), or run timed out, lost a lock race to a concurrently running copy of the same job, or a job it ran exited with a runtime failure (a network error, a bad response).
2 An operator error for status, init, unclaim, unlock, relocate, backup, restore, up, pause or resume: a configuration document that fails to load, a command that can’t run given the current state (init without --force against a data directory that already has one, --lan before claiming, up against a data directory another instance already holds, backup or restore while the box is running, restore into a data directory that already holds settings or with a --vault-dir that is not new or empty, or a backup that is not whole; relocate uses 1, not 2, when the box is running), or run given a TOOL name the shipped manifest doesn’t have: printed as one plain sentence on stderr, never a traceback. run is different: it does not have its own operator-error code. It exits with exactly the connector’s own exit code, unchanged, and that connector reuses 2 for a configuration problem (a missing vault, a secret that was never set) the same way this launcher does, so a failed run can exit 2 for a config problem, not only for a bad TOOL name.

up itself can end at either non-zero code: 2 if it’s refused outright before starting anything (the two cases above), or 1 if it started fine but later gave up on a service that kept crashing fast: every child stops in that case, not just the one that failed.

The component processes, for the curious

maisnie up starts several smaller processes under the hood, each installable and runnable on its own if you’re scripting around Maisnie rather than just using it: the gatekeeper (the one process bound to a network-reachable address), the Desk (python -m desk serve, the setup wizard’s own HTTP surface), and the Surface (python -m surface, the Home/Search/ note-viewer pages): every service ships with the box, so up treats a missing Surface or a missing connector manifest as a broken install and refuses to start, rather than running with a piece silently absent. The Desk and the Surface both bind loopback-only and check no login of their own: they’re reachable through the gatekeeper, or directly by anything else already running on the same machine, which is why nothing but the gatekeeper is meant to be exposed beyond loopback. A fourth package, the gateway, still isn’t a fifth long-running process under up, but it is no longer only library code the Desk imports for the “Save and test” button and connection validation: Ask spawns python -m gateway as its own short-lived subprocess for every question you send it, one process per question, gone again once it answers. None of these need to be run by hand for ordinary use; maisnie up wires all of them together with the right configuration and environment variables already set. The scheduler isn’t a fifth process: it’s a background thread inside up itself, ticking every few seconds to start whichever connector job is due (see connect your accounts); maisnie run/pause/resume are how you reach it from outside without going through the wizard.

Next

Continue to backup.