PM2 supervisor
PM2 daemonizes mikan, restarts it after failures, retains stdout/stderr logs, and can start it on boot.
Run mikan under PM2 with persistent state, managed sandbox images, graceful shutdown, and an optional health endpoint.
PM2 supervisor
PM2 daemonizes mikan, restarts it after failures, retains stdout/stderr logs, and can start it on boot.
Managed image sandbox
The mikan host process uses Docker to create per-conversation tool containers from the selected sandbox image.
Persistent state
Keep one host-only state directory for settings, the office registry, vaults, per-office state, and GitHub polling watermarks.
>=24.15.0~/.mikan for the PM2 user, where mikan keeps its state; the working directory defaults to ~/.mikan/workspaceoci:* or container:*: nerdctl, Podman, or Docker; mikan uses the first one running (see OCI sandbox)The published mikan-sandbox image is a tool runtime, not a standalone mikan server image. PM2 runs mikan on the host; oci mode creates and manages containers through the host Docker daemon.
Install mikan and PM2:
npm i -g @geminixiang/mikan pm2Run the setup as the user PM2 runs under. It asks for the chat platform’s tokens, the LLM
provider, and the sandbox image, then writes ~/.mikan/settings.json, the secrets file
~/.mikan/mikan.env (mode 0600), and the PM2 file ~/.mikan/ecosystem.config.cjs:
mikan onboardEvery secret lives in ~/.mikan/mikan.env, which the ecosystem file loads at start; never put
secrets in the ecosystem file or PM2’s own environment. To add a platform or variable later, edit
that file; mikan env lists every variable and what is currently set. An existing
~/.mikan/ecosystem.config.cjs is kept as it is.
Start and persist the process:
pm2 start ~/.mikan/ecosystem.config.cjspm2 savepm2 startupRun the command printed by pm2 startup to enable boot startup.
The ecosystem file is supervision-only: process name, restart policy, graceful-shutdown timeout,
the mikan.env loader, and the sandbox mode in args (run mikan --help for the flag
reference). Behavior (model, sandbox limits, reply modes) stays in ~/.mikan/settings.json. The
working-directory argument is optional; without it mikan uses ~/.mikan/workspace and creates it
on first start.
Relative workspace paths are resolved from PM2’s current working directory. Absolute paths avoid silently opening a different workspace after service migration or reboot.
npm i -g @geminixiang/mikanpm2 reload mikanIf the new version has pending State migrations, run them before reloading.
After editing ~/.mikan/mikan.env, reload through the ecosystem file so the environment is
re-read:
pm2 reload ~/.mikan/ecosystem.config.cjsA release that changes the format of persisted files ships a numbered migration. The daemon refuses
to start while one is pending and prints the exact mikan migrate command to run; it never converts
files on its own. ~/.mikan/migrations.json records which migrations have been applied.
Check for pending migrations after installing a new version. --dry-run only reads, so it is safe
while the daemon runs. Pass the same --sandbox and workspace the daemon uses:
mikan migrate --sandbox=oci:mikan-sandbox:latest --dry-runIf it prints No pending migrations., reload as above. Otherwise stop the daemon, apply them, and
start it again:
pm2 stop mikanmikan migrate --sandbox=oci:mikan-sandbox:latestpm2 start mikanA migration stops, without being recorded, when it cannot decide safely: for example, a directory
whose name fits several enabled platforms (bare digits with both Telegram and Discord running), or a
conversation present under both an old and a new name. The error names each path and the fix. Name
an ambiguous owner with --owner <conversationId>=<platform> (repeatable) and run again; the
migrations that already succeeded stay applied.
1.0.0 migrates a 0.5.3 install in place. It is the only supported upgrade: formats that existed
only in 1.0.0 prereleases are not converted. Until the migrations run, the 1.0 daemon refuses to
start and prints the mikan migrate command for your install.
Back up. Stop the 0.5.3 daemon and copy both its state directory and its working directory. Migrations rename directories in both.
Install 1.0. It needs Node.js 24.15.0 or newer: npm i -g @geminixiang/mikan@latest.
Move state to ~/.mikan. 1.0 has no --state-dir; if 0.5.3 kept its state elsewhere,
move that directory to ~/.mikan, and remove --state-dir from the command line your process
manager runs.
Choose a supported sandbox. 1.0 runs host, container:<name>, and oci:<image>. A
0.5.3 install on firecracker:* or cloudflare:* must pick one of these first.
Move provider keys. Keys that 0.5.3 read from ~/.pi/mikan/auth.json are not migrated;
set them in ~/.mikan/mikan.env, or keep them in models.json.
Migrate. Pass the 0.5.3 working directory and the sandbox the daemon will run with, preview, then apply:
mikan migrate --workspace /srv/mikan --sandbox=oci:mikan-sandbox:latest --dry-runmikan migrate --workspace /srv/mikan --sandbox=oci:mikan-sandbox:latestStart and check the log. For each settings.json, the daemon logs
Settings that mikan ignores; remove them from <path> with the 0.5.3 keys 1.0 no longer
reads, such as llm.autoReply, and Environment variable that mikan ignores for each
variable it no longer reads, with what replaces it. Remove them; move a sentry.dsn setting to
SENTRY_DSN.
mikan migrate:
host per-user vaults and the container:* vault to hashed identity keys;settings.json into ~/.mikan/conversations/<office-key>/;sessions.db and keeps the original files under ~/.mikan/conversations/<office-key>/sessions-v3/;<workspace>/events/*.json into each conversation’s host-only event store;/root;~/.pi/agent/models.json (or $PI_CODING_AGENT_DIR/models.json) to ~/.mikan/models.json
when mikan does not have one yet;last_prompt.jsonl and auto-reply.disabled from each conversation directory, since 1.0
writes neither.What people notice after the upgrade:
session and stop work without a leading slash; new, model, and auto-reply need
their slash forms, such as /pi-new.on, off, or jev. A channel that had auto-reply rules
now replies to every top-level message; use /pi-auto-reply off or jev to narrow it./workspace/<office-key>. Paths the agent
quoted in earlier sessions point at the old /workspace/<conversation-id> location.skills/ directories still are.The changelog lists every change since 0.5.3, including the narrower package interface for embedders.
The portal server exists only when LINK_PORT is set, or when LINK_URL causes the default port 8181 to be used:
curl http://127.0.0.1:8181/health# {"ok":true}/health is a liveness check for the HTTP process only. It does not verify platform connections, Docker, sandbox provisioning, LLM providers, or event delivery, so do not use it as the only readiness signal.
See the maintained PM2 ecosystem file on GitHub and Sandbox modes for mode-specific requirements.