CLI reference
Running mj without a subcommand starts the per-user daemon when necessary and opens the terminal dashboard. If no workspace exists, it creates one using the current directory name and leaves it ready for an explicit new session. Otherwise it opens the requested workspace or the most recently opened workspace. The terminal surface needs at least 60 columns, and 80 for the Sessions sidebar to sit beside the conversation.
mj [--instance <name>] [--workspace <name>] [command]mj --workspace <name> with no command opens the dashboard in that workspace. Given before a command that works in a workspace, it applies to that command. It is not a global option: the commands that work in a workspace (mj new, mj acp, mj sessions, mj events, mj resume, and mj import) take --workspace <name> after the command name too, and the other commands refuse it there. mj new and mj acp require it. mj sessions and mj events show only that workspace when it is given, and every workspace when it is not. mj import, and mj resume --wiki when it imports another tool’s session, put the session in it and need it when the instance has more than one workspace.
--instance (-i, or MJ_INSTANCE) is global and runs a fully isolated copy — configuration, database, daemon, and logs under instances/<name> (for example mj -i dev daemon status). Hidden worker, broker, daemon-run, and desktop-bootstrap commands are internal implementation interfaces and are intentionally omitted here.
mj acp is listed in mj --help. It is the ACP agent a program starts instead
of a coding harness, and is documented in ACP agent.
Open a surface
Section titled “Open a surface”| Command | Purpose |
|---|---|
mj | Open or attach to the terminal dashboard. |
mj --workspace <name> | Open a particular workspace. |
mj workspaces | Open the workspace manager in the dashboard. |
mj workspaces list [--json] | List workspaces without a terminal. |
mj workspaces create <name> [--json] | Create a workspace, or select the one that already has the name. |
mj go [--setup] [--global-default] [<folder>] | Open the dashboard on a folder (default: the current directory) with its remembered account and target. --setup changes that folder’s setup; --global-default also makes it the default for new projects. |
mj simple [<folder>] | Open the folder’s last running Simple session or start one immediately with the default enabled agent, the local localhost target, and an isolated checkout. Automatic turn review is off for the session. Commands are direct Ctrl-key chords with no prefix, so Ctrl+B remains available to tmux. |
mj app | Open the authenticated web viewer in the separate mj-desktop application. |
Use prefix+q to detach from the dashboard without stopping the daemon or any session. The terminal surface documents its keys; the web viewer covers mj app and browser access.
mj simple is intentionally narrower than mj go: it does not show the
profile, target, project, or review wizard, does not choose a remote or
container target, and does not write its fixed recipe into the folder’s normal
mj go setup. In Simple mode, ctrl+q detaches, ctrl+n starts another
session, ctrl+g opens the session list, and ctrl+f1 lists every command.
Ctrl+B is not a Mjolnir prefix or command.
Daemon control
Section titled “Daemon control”mj daemon statusmj daemon stopmj daemon restartstatusprints the daemon PID, version, start time, connected-client count, and viewer state. When the viewer is ready it also prints the URL and six-digit access code; otherwise it reports disabled, starting, stopped, or error state.stopgracefully stops the controller daemon. Detached workers keep running.restartgracefully replaces the daemon with the installed Mjolnir build and reconnects to existing workers. It refuses when the running daemon’s build is newer than its own; to go back to an older build, runmj daemon stopfirst.
mj setupmj setup instructions --platform linuxmj setup instructions --platform macosmj setup reruns the same automatic agent and repository discovery used on
first interactive startup. It detects installed harnesses and home-directory
overrides, adds profiles and a bundle for the current GitHub origin, and
preserves existing entries and preferences. Matching entries are reused;
identifier collisions get separate names. It also probes every SSH or EC2
machine that has no runtime yet and adds the runtimes it can run. It saves
additions without questions and reports actionable doctor errors. Container
downloads remain background
daemon work. Configure container options, SSH hosts, and AWS targets in Settings;
use mj doctor --smoke for explicit container smoke tests.
setup instructions prints coding-agent-friendly preparation steps for a Linux or macOS host.
Diagnose the installation
Section titled “Diagnose the installation”mj doctormj doctor --jsonmj doctor --smokeDoctor checks configuration compatibility, harness authentication, worker binaries, container runtimes, SSH targets, AWS prerequisites, and Apple Container support. Results are classified as ready, warning, fixable, or unsupported.
--json emits a machine-readable array. --smoke adds real disposable pull/run probes where a target supports them; run it after resolving ordinary fixable checks because it can download an image and provision short-lived resources.
Authenticate a profile
Section titled “Authenticate a profile”mj loginmj login --profile <profile-id>mj login --profile <claude-profile> --setup-tokenThe profile may be omitted only when exactly one is configured. Mjolnir launches the appropriate authentication command for that profile. --setup-token is Claude-only: it mints and stores a long-lived subscription token so containers do not race the controller for a rotating OAuth refresh token.
See profiles and harnesses for home directories, credential handling, and runtime limitations.
GitHub App token
Section titled “GitHub App token”mj github-token --owner <login>mj github-token --repo <owner>/<repository> [--repo <owner>/<repository> ...]Print a currently valid installation token for the configured GitHub App. The
daemon owns the shared token cache; this command does not need the private key
on the caller’s host. --owner returns an installation-wide token. One or
more --repo options discover an installation and limit the token to those
repositories; all selected repositories must belong to the same installation.
The command fails clearly when no GitHub App is configured. Treat its output as
a secret. See GitHub App credentials for setup and CI usage.
Import a native session
Section titled “Import a native session”mj import <harness> (--session <uuid> | --latest) [options]<harness> is one of claude, codex, kimi, grok, or muse. OpenCode
and MiMo Code keep their sessions in SQLite stores and are not importable yet.
| Option | Meaning |
|---|---|
--session <uuid> | Import one native session by its harness ID. Mutually exclusive with --latest. |
--latest | Import the most recently modified native session. |
--profile <id> | Profile whose home holds the session. Needed only when several enabled profiles run this harness. |
--bundle <id> | Associate an existing configured repository bundle. |
--title <text> | Set the title displayed in the dashboard. |
--allow-dirty | Acknowledge that dirty Git roots will be archived in their complete current state. |
--allow-dirty-local | Compatibility alias for --allow-dirty. |
--allow-omitted-non-git | Acknowledge that modified non-Git or scratch directories will be omitted. |
--review-model <name>, --review-effort <name>, --review-tier quick|extended | Review every turn of the imported session with that model or effort. The deprecated tier flag still accepts either value and enables automatic review, but its value is ignored. |
--no-review | Do not review the imported session’s turns automatically. |
--workspace <name> | Workspace to put the imported session in. Needed when the instance has more than one workspace. |
Import never edits the harness’s source transcript. It builds and verifies a Mjolnir recovery archive, creates a suspended session record, and makes that record available through prefix+g.
Examples:
mj import codex --latest --bundle productmj import claude --session 018f2d00-0000-7000-8000-000000000000 \ --bundle product --title "Finish migration"Create a checkpoint
Section titled “Create a checkpoint”mj checkpoint --session <session-id>Creates and verifies a recovery copy for an active session. It waits for a safe dispatch boundary, then lets normal work continue while the archive is packaged where supported. Mjolnir also checkpoints completed idle turns automatically, throttled to roughly one checkpoint per ten minutes.
Move a live session
Section titled “Move a live session”mj move --session <id> [--target <target-id>] [--profile <profile-id>] [--queue discard|start] [--clear-resources] [--yes] [--json] [--prepare] [--allow-large-transfer] [--exclude <repository>:<path>]... [--subagents native|mjolnir|none] [--subagent-straightforward <model>] [--subagent-straightforward-effort <effort>] [--subagent-subtle <model>] [--subagent-subtle-effort <effort>]mj move-sources --session <id> [--cleanup <operation-id> --yes]Move keeps the logical session, workspace, transcript, and recoverable
repository state while rebuilding its execution environment. At least one of
--target or --profile is required; an omitted selector keeps its current
value. The destination must satisfy the same compatibility checks as resume.
Moving between harnesses creates a bounded transcript handoff rather than
copying harness-private process state.
Move inherits the source resource sizing and attached directories by default.
--clear-resources explicitly removes inherited sizing so the destination
uses its configured defaults; attached directories remain part of the fixed
workspace selection.
--subagents native switches to harness delegation; --subagents mjolnir
uses the global task choices in [subagents.straightforward] and, when
configured, [subagents.subtle], or provide a session override for either type.
--subagent-straightforward M and --subagent-subtle M independently override
the matching task choice for this session; each unspecified type uses its global
choice. Either override implies Mjolnir. The matching
--subagent-*-effort flag requires its model flag. Omitted policy retains
the session’s override. --subagents none removes delegation tools entirely;
it needs a Claude or Codex session. A retry of a sealed
Move retains its recorded policy; an explicit different policy is refused.
A session that works in a bare checkout on an SSH host cannot move to
another machine. Its working tree is the checkout itself, so --target is
refused with this session's working tree lives on <host>; resume it there.
Such a session can change profile in place, or move to another bare target on
the same host; that Move is the same in-place profile switch, keeping the
checkout and transferring no files. To continue elsewhere, push its branch and start a new session
from that branch. The same rule applies to mj resume --target.
When the move copies a workspace, it transfers the repository history and tracked edits, plus the untracked files you keep selected. Three flags control that selection:
--prepareinspects the transfer and prints the preparation as JSON without moving anything. Use it to see the eligible files, their sizes, and any blockers.--exclude <repository>:<path>leaves an untracked file or directory at the source. Repeat it for each path.--allow-large-transferaccepts a workspace transfer of at least 1 GB. Without it, a large selection is refused, and the error says which of these flags can resolve it.
Paths left behind stay in a retained source. mj move-sources --session <id>
lists the retained sources for a session as JSON. To delete one together with
its excluded files, pass its operation ID as --cleanup <operation-id> and
confirm with --yes; --cleanup without --yes is refused.
An interactive invocation prepares the destination and asks for confirmation.
--yes confirms the interruption for unattended use, but it does not choose
what to do with queued work. If commands are pending, unattended use must pass
--queue discard or --queue start; discard is the default only in an
interactive confirmation. For start, commands are accepted in their
original order after destination readiness. The interrupted active prompt is
never replayed.
Human output reports the operation ID and phase progress. --json suppresses
progress on stdout and emits one final object containing the operation ID,
session ID, resolved profile and target, outcome, and any recovery guidance.
Failures return a nonzero status. Ctrl-C requests cancellation from the daemon;
disconnecting a client does not cancel a detached move.
Upgrade a session container
Section titled “Upgrade a session container”mj upgrade-container --session <id>mj upgrade-container --session <id> --acknowledge-writable-layer-lossmj upgrade-container --session <id> --cancelThe first command previews the inspected current image, selected target and preservation warning. The acknowledgment queues a durable request; accepted work finishes before replacement starts. Workspace and build-cache mounts are retained. Writable-layer files, including manually installed packages, may be lost. A checkpoint does not preserve the whole environment. Pending requests survive daemon replacement and can be cancelled before replacement begins. Unsupported storage layouts fail before the worker is stopped. Normal Restart agent keeps the existing container and its filesystem.
Recover untracked resources
Section titled “Recover untracked resources”mj recover scan [--json] [--all-instances]mj recover adopt --session <id> --target <id> [--profile <id>] [--bundle <id>] [--all-instances]mj recover destroy --session <id> --target <id> --confirm <id> [--all-instances]scanlists Mjolnir-managed workers that exist on a target but are absent from controller state. By default it lists only workers this Mjolnir instance created (the--instancename, or a fingerprint of the data directory).--all-instancesalso lists workers created by other instances and workers from older builds that carry no instance stamp; the plain output shows which instance created each one.adoptprobes a worker and adds it back to state.--profileand--bundleare needed only for older current-v1 workers created before ownership markers were recorded. Adopting a worker from another or an unknown instance requires--all-instances.destroydeletes an untracked managed resource.--confirmmust repeat the exact session ID to make accidental deletion harder, and a worker from another or an unknown instance is refused without--all-instances.
Inspect scan output before adopting or destroying anything. See session recovery and durability for the surrounding guarantees.
Drive a session from another agent
Section titled “Drive a session from another agent”mj workspaces list [--json]mj workspaces create <name> [--json]mj new (--workspace <name> | --workspace-id <id>) [--profile <id>] [--target <id>] [--bundle <id>] [--project-directory <path>] [--at <sha>] [--branch <name>] [--base <revision>] [--title <text>] [--model <name>] [--effort <name>] [--subagents native|mjolnir|none] [--subagent-straightforward <model>] [--subagent-straightforward-effort <effort>] [--subagent-subtle <model>] [--subagent-subtle-effort <effort>] [--review-model <name>] [--review-effort <name>] [--review-tier quick|extended] [--no-review] [--no-project-memory] [--no-github-events] [--cpus <count>] [--memory-gib <GiB>] [--prompt-file <path>] [<prompt>|-] [--json]mj prompt --session <id> [<text>|-] [--prompt-file <path>] [--command-id <id>] [--timeout <seconds>] [--return-on-input] [--json]mj message --session <id> [<text>|-] [--prompt-file <path>] [--command-id <id>] [--json]mj wait --session <id> [--turn <turn-id>] [--timeout <seconds>] [--return-on-input] [--json]mj transcript --session <id> [--after-seq <seq>] [--limit <count>] [--role <role>]... [--finished-only] [--json]mj diff --session <id> [--base <revision>] [--json]mj export --session <id> [--kind patch|branch|bundle] [--branch <name>] [--out <path>] [--json]mj fetch --session <id> --path <path> [--stdout | --ls] [--json]mj sessions [--session <id>] [--all] [--workspace <name>] [--json]mj suspend --session <id> [--acknowledge-unpublished-work] [--json]mj destroy --session <id> [--delete-branch] [--json]mj resume (--session <id> | --wiki <sessionwiki-id>) [--profile <id>] [--target <id>] [--workspace-id <id>] [--workspace <name>] [--queue start|discard] [--json]mj interrupt-turn --session <id> [--json]mj review start --session <id> [--json]mj review status --session <id> [--json]mj review (forward | dismiss | cancel) --session <id> [--json]mj stop-task --session <id> (<task-id> | --all) [--json]mj api-info [--json]mj events [--session <id>] [--workspace-id <id>] [--workspace <name>] [--after-seq <seq>]mj usage --session <id> [--after-seq <seq>] [--limit <count>] [--json]mj put-file --session <id> --path <workspace-relative path> [--overwrite] [--json] <source>|-mj elicitations --session <id> [--json]mj respond --session <id> --elicitation <id> [<response JSON>|-] [--response-file <path>]mj models --profile <id> [--model <name>] [--json]mj set-config --session <id> [--key <key> --value <value>] [--json]mj new --at <sha> starts the workspace checked out at that full commit ID in
the bundle’s primary repository, before the first prompt. It requires
--bundle. With --at, --branch <name> creates that new branch at the
commit; without --branch, HEAD is detached. Without --at, --branch <name>
selects an existing branch to check out in a new isolated clone; otherwise the
clone starts on the remote default branch. --base <revision> records the diff
base for mj diff when it should not be --at; it defaults to --at and does
not move the checkout. A local clone resolves the base in the source
repository, while a network clone resolves it from fetched Git history. A base
cannot be combined with a session that runs directly in the selected directory.
mj newwithout--profileor--targetuses the saved default for the missing one (the pairGET /api/v1/optionsreports asdefault).mj new --model <name>chooses the highest-quota enabled, usable profile offering that exact model and starts the session on it. It conflicts with--profile; the saved default profile breaks quota ties. If--effortis supplied, the selected profile must offer that exact effort for the model or the request fails.mj new --subagents native|mjolnir|noneselects delegation. Omitted defaults to Native.nonegives the session no delegation tools, native or Mjolnir; it needs a Claude or Codex profile and is not offered in the TUI or browser. Mjolnir requires a Claude or Codex parent and a straightforward choice in[subagents.straightforward]or a session override. The subtle choice in[subagents.subtle]is optional. Configure global defaults in config.toml or TUI Settings → Sub-agents.--subagent-straightforward Mand--subagent-subtle Moverride only their named task type; an unspecified type uses its global choice. Either implies--subagents mjolnirand cannot be combined withnativeornone. Each effort flag requires its matching model flag; omitted effort uses the harness default andadaptiveis invalid. The retired--subagent-modeland--subagent-effortflags fail with guidance to use the four per-type flags.single-modelandall-modelsremain rejected. When both types are configured, each spawn selectsstraightforwardorsubtle. With only straightforward, the spawn tool has no task type, every child uses the straightforward choice, and the parent is told to delegate straightforward work. Mjolnir chooses an eligible profile offering its model and effort by quota.mj new --review-model <name>,--review-effort <name>and--review-tier quick|extendedreview every turn of the new session with that model or effort, even when[review]is off. The deprecated tier flag still accepts either value and enables automatic review, but its value is ignored.--no-reviewturns off automatic review for the session, even when[review]is on;/reviewstill works.mj import <harness>takes the same flags for the session it adopts. See per-session settings.mj new --no-project-memorystarts the session with no project memory: nothing from the workspace’s project memory is put in the agent’s startup context, and the harness is offered no memory directory to write to. Its sub-agents get none either. Use it when a session must see only its checkout and its prompt, as an evaluation run does. Without the flag the session loads the workspace’s project memory as before. See project memory.mj new --no-github-eventsprevents the GitHub watcher from registering the session as a delivery target. Its sub-agents inherit the flag. This is the flag’s only effect.[github.watch] enabledand[jev] enabledcontrol GitHub event production.- On a container target,
mj newgives the session the same CPU and memory limit that the dashboard and the web viewer select: the size last chosen for that host, else 8 CPUs and 32 GiB, capped at the host’s totals.--cpus <count>and--memory-gib <GiB>override either one. Other targets refuse both options. --return-on-inputmakesmj promptandmj waitreturn as soon as the agent asks for structured input, with the outcomeinput_required. Answer withmj elicitationsandmj respond, then wait again.- By default,
mj transcriptomitstoolandterminalentries. Repeat--roleto select several kinds of entry fromuser,agent,thought,tool,terminal,plan,plan_proposal, andsystem. To include every kind, list all eight roles; there is no--all-rolesoption.--finished-onlyselects closed agent messages and can be combined only with--role agent; it implies theagentrole when no role is given. mj eventsprints durable session events as line-delimited JSON, following new events until you stop it.--after-seqreplays from that sequence first.mj usagereads recorded token usage for a session.mj put-fileuploads a file, or standard input with-, into an idle session’s workspace. It refuses to replace a file unless you pass--overwrite.mj fetchcopies a file, or a directory as a zip archive, from a session’s target to this machine and prints where it landed. See below.mj modelslists the models and efforts a profile offers.mj set-configapplies one session setting, such as the model or effort. Without--keyand--valueit lists the settings the session’s agent offers, with their choices.
mj diff compares against the recorded launch base by default. Use --base
to compare against an explicit Git commit or revision, for example after
checking out an older task base. This does not change the session’s recorded
baseline. --json returns diff, base, head, and head_descends_from_base;
base and head are resolved commit IDs. The patch includes committed, staged,
unstaged, and untracked work. An unknown base is refused. mj diff asks the
worker for the metadata either way, so both forms need a worker that supports
it; an older worker reports that the session needs upgrading.
When head_descends_from_base is false, the session’s HEAD is no longer a
descendant of the base — the agent rebased, amended, or reset — so the diff
carries history changes as well as session work. Without --json, mj diff
writes the patch to standard output and one warning: line to standard error
saying so. An older worker leaves the field out, and no warning is printed.
Every session lives in a workspace that the dashboard and the web viewer list,
so mj new needs --workspace <name> (or --workspace-id <id>). Without it,
mj new fails, lists the instance’s workspaces with their session counts, and
says how to create one. A fresh instance has no workspace. Run mj workspaces create <name> first. It selects the workspace when the name already exists, so
a script can run it every time:
mj workspaces create agentsmj new --workspace agents --project-directory . "Fix the failing test"The terminal dashboard still names its first workspace after the directory it
was started in. A store from an earlier release that holds sessions made
without a workspace lists them in a workspace named default.
mj sessions lists top-level sessions by default. Add --all to include
Mjolnir sub-agents.
These commands run one Mjolnir session as a subagent: mj new starts it with a
first prompt and prints its id, mj wait blocks until the turn ends and prints
the outcome, the elapsed time, the number of tool calls, and the agent’s final message,
and mj prompt does both for the next prompt. A prompt comes from the
positional argument, from --prompt-file, or from standard input when the
argument is -; mj message takes its text the same way.
Each command has one behavior: mj prompt always waits, and mj message
never does.
mj prompt --session <id> <text> sends the text as your prompt and waits for
that turn to end. Before it waits, it prints turn N on standard error, so if
the wait is cut off you can go on with mj wait --session <id> --turn N. With
--json, standard output holds only the wait’s result. --command-id <id>
makes the send safe to retry: after an ambiguous reply, run the same command
with the same ID and you get the same turn, not a second prompt. The retired
--wait flag is still accepted and changes nothing. Because a prompt sent this
way reads exactly as your own, mj prompt refuses to run inside a session
(when MJ_SESSION_ID is set); an agent sends with mj message and follows
with mj wait.
mj message --session <id> <text> sends and returns. From your own shell
(MJ_SESSION_ID not set), it submits the text as your prompt, just as
mj prompt does: the session starts a turn with it, takes it into the running
turn, or queues it. It prints turn N; follow it with
mj wait --session <id> --turn N when you want the result. --command-id <id>
makes it safe to retry in the same way. Inside a session (MJ_SESSION_ID
set), mj message sends a message to another top-level session, or to one of
the caller’s own sub-agents. Messages from sessions show the sender’s title and
full ID, with a reply instruction, and --command-id identifies the message
across retries.
The first line of a wait says how the turn ended in the same words as
mj sessions --session <id>, for example
turn finished (completed, end of turn) in 5.3s · 4 tool calls or
turn error (failed: harness inactive) in 30.3s. The tool-call count appears
when the turn made any. The line carries no turn number: the number mj prompt
and mj message print is the handle mj wait --turn takes, not a count. With --json, the
stop_reason field keeps the harness’s own spelling, such as EndTurn, and
turn_id and tool_calls are separate fields.
mj wait answers one of two questions:
mj wait --session <id> --turn <turn-id>waits until that turn has ended and says how. The turn ID is the numbermj newandmj messageprint. A server retry of the turn is part of it, but nothing that starts new work is: not a turn the agent starts on its own, background work it left running, or Mjolnir’s automatic continuation. When the session is still busy as the wait answers, the first line ends with what it is doing, in the dashboard’s words, for exampleturn finished (completed, end of turn) in 5.3s; the session is not idle: [BG 2m10s].--jsoncarries it asnext.mj wait --session <id>without--turnwaits until the session settles: the agent is idle, nothing is queued, and the session can take a prompt. That includes turns the agent starts on its own, so it can keep waiting long after your prompt’s turn ended. To learn when your prompt’s turn ended, pass--turn, or usemj prompt.
mj resume continues a session that mj suspend suspended. The session keeps its
id, its transcript, and its work; Mjolnir provisions a fresh target and restores
the verified checkpoint. Every selector is optional: the session’s own record
supplies the profile, the target, and the workspace, so mj resume --session <id> is the whole command for continuing where you left off. --profile and
--target resume somewhere else, and --queue decides whether prompts queued
when the session was suspended are started or discarded (start by default).
mj resume --wiki <sessionwiki-id> continues a session found in the
SessionWiki index, whoever ran it, so an agent that searched for earlier work
does not have to decide what kind of row it found. Mjolnir takes one of three
branches and says which one it took. A Mjolnir session it still has a record of
is resumed exactly as --session resumes it. A Mjolnir session whose record the
archive job destroyed is restored: a new session starts with a compacted
hand-off from the indexed transcript, using --profile and --target when
given and the profile and target recorded in the index otherwise. Another tool’s
session (Claude Code, Codex, Kimi Code, Grok Build, Muse) is imported from that
harness’s own home and then resumed, which needs the session to still be there;
the error names the indexed path so you can import it by hand if it is not.
--wiki and --session are mutually exclusive, and --json answers with
action (resume, restore or import), session_id and wiki_id.
mj sessions --session <id> accepts a SessionWiki id too. An id that names no
Mjolnir session is looked up in the index and reported as mine, archived or
native, with the tool, the indexed path and the Mjolnir session id when there
is one, so an agent can explain what it found before it continues it.
The command answers as soon as the daemon has taken the session, because
restoring an archive takes minutes. Follow it with mj wait --session <id>,
which blocks while the resume runs and reports the reason if it fails, and then
mj set-config, mj prompt and mj message as for any live session. A session that is
already running is refused: suspend it first. mj move is the command for a live
session that should continue elsewhere.
mj sessions --json and mj sessions --session <id> --json include
background_tasks, with each task’s opaque id, command, started_at_ms,
and can_stop. Use mj stop-task --session <id> <task-id> to stop one task,
or --all to request stops for every currently listed stoppable task.
Unsupported tasks are skipped and reported. With --json, the result contains
session_id, accepted_task_ids, skipped_task_ids, and a failures object
mapping task IDs to errors. All selected stops are attempted; any failure makes
the command exit nonzero. Acceptance does not establish that the task has exited:
inspect the session again to confirm it disappeared.
mj suspend saves a verified recovery copy and releases the environment. It
reports acceptance; follow it with mj wait --session <id> to observe completion
or a reported failure. A session’s active Mjolnir sub-agents are stopped
without a recovery copy of their own, and only the session is suspended. When
some of them have not handed back their reports, mj suspend prints a warning
on standard error, such as warning: 2 sub-agents have not handed back; suspending stops them. With --json the answer carries stopped_subagents,
subagents_not_handed_back, and warning (omitted when there is none). When the
session resumes, its agent is told which sub-agents were stopped. For an
independent clone whose work may be unpublished,
pass --acknowledge-unpublished-work after reviewing the warning; suspension
still verifies the recovery copy before releasing the clone. mj interrupt-turn interrupts only the current turn and
keeps the session available for another prompt.
mj review start reviews the turn a session just finished with the session’s
reviewer, as /review does in Prompt. It answers once the review has opened,
which can take a few minutes while a reviewer is chosen and started, and fails
with the reason when the session is still working, has queued prompts, is a
sub-agent, or has no usable reviewer. mj review status prints the open
review’s status, reviewer role, and verdict, or no review is open.
mj review dismiss and mj review cancel close the open review, for example a
failed one, so another can start; mj review forward retries a forward the
primary refused. See turn review.
mj destroy permanently removes the live session record, environment, and
recovery archive. Its conversation is indexed in SessionWiki first:
mj sessions --session <id> can find the archived conversation, and
mj resume --wiki <id> starts a new session from it. That restores conversation
context, not the deleted checkout or unexported files.
New managed clones have no branch in the source repository. For older linked
worktree sessions, the managed branch remains unless --delete-branch is
specified. mj close was removed: use mj suspend to keep the session, or mj destroy to
remove it (this replaces mj close --force). mj cancel-turn was removed too;
use mj interrupt-turn. Both old names fail with a notice naming their
replacement and perform no lifecycle action.
mj export writes a patch or a bundle to --out, or to standard output when
no file is named; --kind branch pushes the session’s work and reports the
branch and remote instead. With --json and --out, mj export prints one
object with the path, the bytes written, and the format (patch or
bundle); with --json and no --out the export itself is still the output.
mj fetch reads a path on a session’s target, which may be another host or a
container, so one session can read evidence another session cites. A relative
--path resolves in the directory the session’s agent runs in; an absolute
one is read as the target spells it. After symlinks are resolved, the path
must lie in the session’s workspace, its sub-agent report directories, or the
target’s temporary directory. A file is copied as it is, up to 16 MiB. A
directory arrives as a zip archive of at most 16 MiB, made from at most
128 MiB of files; symlinks inside it are stored as links, not followed. The
copy lands in $TMPDIR/mjolnir/<session>/ followed by the path on the target,
with .zip after a directory’s name, and mj fetch prints that local path.
For example, mj fetch --session d8443f17… --path /tmp/rust-veto-cf prints
/tmp/mjolnir/d8443f17…/tmp/rust-veto-cf.zip. With --json it prints the
local path, the kind (file or directory), the source path on the
target, and the bytes written. --stdout writes the file, or the zip
archive, to standard output instead.
mj fetch --ls lists the path on standard output instead of copying it: a
directory’s entries in name order, or the file itself. Each line gives the size
in bytes (- for a directory), the modification time in UTC, and the name,
with / after a directory and -> target after a symlink. Symlinks are listed,
not followed. With --json it prints the resolved path and an entries
array; each entry has name, kind (file, directory, symlink, or
other), size, modified (RFC 3339, or null when the target records none),
and target for a symlink. mj transcript
pages by --after-seq; use the response’s next_after_seq for the next page.
The selected roles are filtered before the page limit. The cursor advances
across entries outside that selection, so a page with no matching items can
still make progress. latest_seq is the newest sequence in the full transcript.
--limit sets a target number of matching items per page; tied entries with
the same sequence stay together, so a page can exceed the target.
With --finished-only, next_after_seq is an exclusive resume cursor for the
finished agent prefix: it never passes the sequence of the earliest currently
open agent message. If the page reaches that open message, the cursor stops at
the preceding sequence; poll again with that exact cursor, and the message is
returned after its body reports streaming: false. If the page limit is
reached first, the cursor is the last returned sequence. With no open agent
message remaining, it can advance across non-agent rows to latest_seq, even
when the page has no items. Here, “finished” means the stored stream was closed
at the time of the read. ACP can still append late chunks to the same
stable_id; a consumer that deduplicates only by stable_id may ignore that
later revision.
Each command in this section except mj events and mj respond takes
--json to print its JSON result. For mj transcript, the server applies the
default role selection or the repeated --role selection before paging, and
returns next_after_seq and latest_seq with the response. --finished-only
filters agent messages and uses the finished-prefix cursor described above.
mj events always prints JSON lines.
mj checkpoint, mj login, mj app, mj go, mj setup, and the
mj daemon commands do not take --json. The commands in this section are
clients for the HTTP API, which documents the routes,
the wait outcomes, the export preconditions, and the bearer token these
commands read. mj api-info prints the base URL and the token file.
Operator environment variables
Section titled “Operator environment variables”Most behavior belongs in configuration. These environment variables select filesystem locations or companion binaries before configuration loads:
| Variable | Purpose |
|---|---|
MJ_CONFIG_DIR | Directory containing config.toml; overrides the platform config directory. |
MJ_DATA_DIR | Root for Mjolnir’s database, logs, archives, and other local state. |
MJ_WORKER_BINARY | Explicit target-compatible worker binary. |
MJ_WORKER_DIR | Directory searched for bundled worker binaries. |
MJ_WORKER_URL | Remote worker URL fallback; it may contain {target} and requires MJ_WORKER_SHA256. |
MJ_WORKER_SHA256 | Required 64-character hexadecimal digest when MJ_WORKER_URL is set. |
MJ_DESKTOP_BINARY | Explicit mj-desktop executable used by mj app. |
MJ_CONTROLLER_BINARY | Explicit controller executable used by companion launchers. |
MJ_VOICE_WORKER | Explicit local voice-worker executable. |
CODEX_HOME | Codex home used by setup discovery and native import. |
CLAUDE_CONFIG_DIR | Claude Code home used by setup discovery and native import. |
KIMI_CODE_HOME | Kimi Code home used by setup discovery and native import. |
GROK_HOME | Grok Build home used by setup discovery and native import. |
MIMOCODE_HOME | MiMo Code profile root used by setup discovery; contains config/ and data/. A profile at the conventional ~/.mimocode home uses the stock ~/.config/mimocode and ~/.local/share/mimocode trees instead. |
XDG_CONFIG_HOME, XDG_DATA_HOME | Muse configuration and external native session storage roots, respectively. |
GH_TOKEN / GITHUB_TOKEN | GitHub token available for syncing into every live target except a bare runtime on this machine. |
GIT_SSH_COMMAND | SSH command used by checkpoint/archive Git operations. |
RUST_LOG | Controller logging filter. |
Setting MJ_WORKER_URL requires MJ_WORKER_SHA256; an unverified downloaded worker is not accepted. A digest set without a URL is ignored.
Run mj <command> --help for Clap’s installed-version spelling and option summary. Continue to troubleshooting for logs, target diagnosis, and common command failures.