Repository navigation
Releases
1.5.1
What's changed
Highlights
- Slack runs continue after a restart (ADR 0027): a reply or task that a deploy or crash interrupts now continues after the restart. mikan posts "Restarted for an update; continuing." in the conversation where the run was replying, and pi-durable continues the same turn; the model is told that the step in progress was interrupted, checks what it already did, and reruns it when that is safe. Only the conversations whose run was interrupted get the notice.
- Faster deploys: shutdown no longer waits up to five minutes for Slack runs, because they continue after the restart. Telegram, Discord, and GitHub keep the five-minute drain.
- codemode scripts have no default deadline, as in Pi. mikan stopped every script after 60 seconds, which cut off slow tool calls; an agent then often sent the same work again while the first attempt was still running on the other side. A script's own
timeout_msstill applies.
Notable changes
- Tasks continue the same way as other runs, without the earlier limit of two automatic resumes.
jev_browserwith onlyurlopens the page and returns its final URL and title.jev_browserno longer refuses a call whosehandOffis an empty string; an emptyhandOffandframe: "main"count as not given.
Upgrade steps
- The first deploy of 1.5.1 still stops a 1.5.0 process, which waits for its runs as before; later deploys stop in about a second.
- An interrupted tool call may run twice: the model sees that it was interrupted and decides whether to repeat it.
- A message waiting behind a running reply, not yet started when the process stops, is lost, as before. Offices idle for more than 24 hours still abort interrupted work when next opened.
Verification
- CI and the Slack E2E suite pass on the merged changes. Continuation was measured with a real model (5 trials per case) and run against a local Slack workspace: channel thread, channel top level, direct message, and
SIGTERM, each interrupted during a 90-second command and answered after the restart.
1.5.0
What's changed
Highlights
- Office desktop (
/pi-desktop): a private 24-hour link to the conversation's desktop in the managedocisandbox. Watch or use the browser the agent drives, open its tabs, DevTools, or a terminal. "Take control" pauses the agent's browser until you hand it back, and the agent can hand you a step such as signing in withjev_browser'shandOff(direct messages only), which posts the step with a link and ends its turn. The desktop starts on the first link, stops with the sandbox's idle stop, and keeps the sandbox running while someone has it open. - mikan keeps its Slack app configured (ADR 0026): with a Slack app configuration token, every start replaces the app's configuration with the manifest of the running release, so new slash commands, scopes, and events need no edit in Slack's settings.
mikan onboardcan create the app,mikan slack tokenconnects an existing one, andmikan slack set --name … --description …customizes it. When a release adds a scope, mikan DMs the token's owner a reinstall link. Without a token nothing changes. - Pi 1.2.0: Pi 1.2 removed an export mikan 1.4.0 imports, so a fresh install of 1.4.0 fails to start; this release works with it. Upgrade from 1.4.0 now.
Notable changes
- A nonzero
bashexit is now an error result that carries the output and the exit code, instead of a thrown error. jev_browsercloses only tabs it opened when it passes its three-tab limit, so tabs a person opened stay open.- The sandbox image adds
sway,wayvnc, andfoot(about 1 MB) and themikan-desktopscript. mikan slack set --namealso names the bot user when Slack accepts the name (letters, digits, spaces,.,_,-); other names, such as Chinese ones, keep the bot namedmikan.
Removed
- The Slack App Home tab, which listed running tasks and scheduled jobs with force-stop buttons. The manifest turns the tab off; a synced app loses it on the next start, and an app configured by hand keeps an empty tab until it is turned off in Slack's App Home settings. Use the stop command or the Admin portal to stop work.
Upgrade steps
- The desktop needs this release's sandbox image. An office whose container still runs an older image gets it after the container idles out and is replaced.
- Register
/pi-desktopin your Slack app, or store a configuration token withmikan slack tokenand let mikan do it on the next start. - Storing a token replaces the whole app configuration: settings added by hand in Slack's pages are removed, and an app built from the agent manifest loses the agent surface. Give one token to one mikan install, because every rotation revokes the previous token.
- Desktop links are bearer links like
/sessionand/adminlinks: anyone holding one can open the desktop until it expires.
Verification
- CI and the Slack E2E suite pass on the merged changes; acceptance evals for the desktop and for the Slack app sync ran against real containers and a real Slack app.
1.5.0-beta.0
What's changed
Highlights
- Office desktop (
/pi-desktop): a private 24-hour link to the conversation's desktop in the managedocisandbox. Watch or use the browser the agent drives, open its tabs, DevTools, or a terminal. "Take control" pauses the agent's browser until you hand it back, and the agent can hand you a step such as signing in withjev_browser'shandOff(direct messages only), which posts the step with a link and ends its turn. The desktop starts on the first link, stops with the sandbox's idle stop, and keeps the sandbox running while someone has it open. - mikan keeps its Slack app configured (ADR 0026): with a Slack app configuration token, every start replaces the app's configuration with the manifest of the running release, so new slash commands, scopes, and events need no edit in Slack's settings.
mikan onboardcan create the app,mikan slack tokenconnects an existing one, andmikan slack set --name … --description …customizes it. When a release adds a scope, mikan DMs the token's owner a reinstall link. Without a token nothing changes. - Pi 1.2.0: Pi 1.2 removed an export mikan 1.4.0 imports, so a fresh install of 1.4.0 fails to start; this release works with it.
Notable changes
- A nonzero
bashexit is now an error result that carries the output and the exit code, instead of a thrown error. jev_browsercloses only tabs it opened when it passes its three-tab limit, so tabs a person opened stay open.- The sandbox image adds
sway,wayvnc, andfoot(about 1 MB) and themikan-desktopscript. mikan slack set --namealso names the bot user when Slack accepts the name (letters, digits, spaces,.,_,-); other names, such as Chinese ones, keep the bot namedmikan.
Upgrade steps
- The desktop needs this release's sandbox image. An office whose container still runs an older image gets it after the container idles out and is replaced.
- Register
/pi-desktopin your Slack app, or store a configuration token withmikan slack tokenand let mikan do it on the next start. - Storing a token replaces the whole app configuration: settings added by hand in Slack's pages are removed, and an app built from the agent manifest loses the agent surface. Give one token to one mikan install, because every rotation revokes the previous token.
- Desktop links are bearer links like
/sessionand/adminlinks: anyone holding one can open the desktop until it expires.
Verification
- CI and the Slack E2E suite pass on the merged changes; acceptance evals for the desktop and for the Slack app sync ran against real containers and a real Slack app.
1.4.0
What's changed
Highlights
web_fetch: the agent reads a public web page or API and checks versions, releases, and dates against the official source instead of answering from memory. HTML comes back as Markdown without navigation; long results are bounded with the full text saved in the workspace. No key needed; private, loopback, and link-local addresses are refused, including through redirects.- OCI sandbox on nerdctl, Podman, or Docker: mikan detects the engine (nerdctl → Podman → Docker);
CONTAINER_ENGINEpins one. - Sandbox image follows mikan:
--sandbox=ociwithout an image usesghcr.io/geminixiang/mikan-sandbox:<mikan version>. mikan pulls it in the background at startup, replaces a stopped office's container when the image changed, and after any replacement removes the previous image once no container uses it, keeping an image that still has another name.
Notable changes
--sandbox=image:<image>is renamed--sandbox=oci:<image>.image:still works with a deprecation warning until the next major release.- Container tools run through Pi's
pi-envdaemon: operations take about 1 ms instead of 40–180 ms, and commands end when mikan disconnects. String commands usebashwhen available. - Each office with a running container keeps one
<engine> exec -iclient process on the host for itspi-envconnection. - Containers get the host's time zone; the sandbox image no longer hardcodes
Asia/Taipeiand is about 390 MB smaller (novim,nano,less, and similar interactive tools).
Security
- With a vault resolver, a tool call that arrives before the conversation's environment is resolved fails instead of running on the host.
- Container credentials travel over the
pi-envconnection, not command arguments or a host-side env file.
Upgrade steps
- Existing containers are recreated once on first use. Workspace and vault mounts are kept; packages installed inside the container are not.
- On a host running more than one container engine, mikan may switch engines; set
CONTAINER_ENGINE=dockerto keep Docker. - Replace
image:withoci:in PM2 ecosystem files or start scripts, or use--sandbox=ocito follow mikan's version. - Deployments that reach the web only through an HTTP proxy cannot use
web_fetch.
Verification
- CI passes on the release commit; the Slack E2E suite passed on the 1.4.0-beta.0 commit.
- 1.4.0-beta.0 ran on a production deployment: no new errors or restarts;
web_fetch, the browser tool, codemode with MCP, and sandbox commands completed in real conversations. web_fetch: 10 current-fact questions with a real model went from 2 correct to 10 correct.- Sandbox: Pi environment conformance and real-container tests pass on Docker, Podman, and nerdctl.
See CHANGELOG.md for details.
1.4.0-beta.0
What's changed
Highlights
web_fetch: the agent reads a public web page or API and checks versions, releases, and dates against the official source instead of answering from memory. HTML comes back as Markdown without navigation; long results are bounded with the full text saved in the workspace. No key needed; private, loopback, and link-local addresses are refused, including through redirects.- OCI sandbox on nerdctl, Podman, or Docker: mikan detects the engine (nerdctl → Podman → Docker);
CONTAINER_ENGINEpins one. - Sandbox image follows mikan:
--sandbox=ociwithout an image usesghcr.io/geminixiang/mikan-sandbox:<mikan version>. mikan pulls it in the background at startup, replaces a stopped office's container when the image changed, and removes the old image once unused.
Notable changes
--sandbox=image:<image>is renamed--sandbox=oci:<image>.image:still works with a deprecation warning until the next major release.- Container tools run through Pi's
pi-envdaemon: operations take about 1 ms instead of 40–180 ms, and commands end when mikan disconnects. String commands usebashwhen available. - Each office with a running container keeps one
<engine> exec -iclient process on the host for itspi-envconnection. - Containers get the host's time zone; the sandbox image no longer hardcodes
Asia/Taipeiand is about 390 MB smaller (novim,nano,less, and similar interactive tools).
Security
- With a vault resolver, a tool call that arrives before the conversation's environment is resolved fails instead of running on the host.
- Container credentials travel over the
pi-envconnection, not command arguments or a host-side env file.
Upgrade steps
- Existing containers are recreated once on first use. Workspace and vault mounts are kept; packages installed inside the container are not.
- On a host running more than one container engine, mikan may switch engines; set
CONTAINER_ENGINE=dockerto keep Docker. - Replace
image:withoci:in PM2 ecosystem files or start scripts, or use--sandbox=ocito follow mikan's version. - Deployments that reach the web only through an HTTP proxy cannot use
web_fetch.
Verification
- CI and the Slack E2E suite pass on the release commit's parent.
web_fetch: 10 current-fact questions with a real model went from 2 correct to 10 correct.- Sandbox: Pi environment conformance and real-container tests pass on Docker, Podman, and nerdctl.
See CHANGELOG.md for details.
1.3.0
What's changed
Highlights
/compact [instructions](/pi-compactin Slack) summarizes a session's older messages with pi-durable's compaction to free up context, in DMs and at a channel's top level, and reports the context size before and after. Earlier messages stay in the session history.- Codemode
store(key, value)andload(key)keep JSON values across scripts in a conversation, as in Pi. Values survive a restart, a thread started from a run sees the values as of that run, and/newclears them.
Upgrade steps
- Run
mikan migrateafter upgrading. The new step0013-session-usagerecords the spend of sessions imported from 0.5.3 in pi-durable's usage ledger; the daemon does not start while it is pending. - Existing Slack apps must add
/pi-compactto their slash commands. The example manifests include it.
Notable changes
- MCP tool results reach the model through pi-mcp's
toLlmContent, so an image embedded as a resource is passed to the model as an image. - Slack DM tasks are found, and their status and acknowledgement read, from pi-durable's task records instead of
log.jsonl, so task status keeps working after a lost or rotated log. Task threads started before 1.1.0 are no longer recognized as tasks, and tasks started from 1.1.0 to 1.2.2 list without their acknowledgement.
Fixes
- The Admin portal's usage views count each session's own spend: a thread started from the run that caused it no longer repeats its parent's spend. Totals now include failed attempts and compaction.
/newin a DM no longer waits for running background tasks or other DM threads (#158).
Verification
- CI and the Slack E2E workflow pass for each change.
- Each change was checked with an acceptance eval against the previous
main, and on a local Slack daemon. - 1.3.0-beta.1 ran on a production deployment:
mikan migratecompleted, and/pi-compactworked in a DM.
See CHANGELOG.md for details.
1.3.0-beta.1
What's changed
Fixes
mikan migratestep0013-session-usageno longer stops withCannot read properties of undefined (reading 'input')on an answer imported from 0.5.3 that recorded no usage, and the Admin portal's daily usage chart no longer drops a session holding one; such answers count as no spend. A partial run of the step from 1.3.0-beta.0 is safe to repeat.
Upgrade steps
Same as 1.3.0-beta.0: run mikan migrate after upgrading, and add /pi-compact to existing Slack apps.
Verification
- CI passes; a test reproduces the failing migration with an imported answer that has no usage record.
See CHANGELOG.md for details.
1.3.0-beta.0
What's changed
Highlights
/compact [instructions](/pi-compactin Slack) summarizes a session's older messages with pi-durable's compaction to free up context, in DMs and at a channel's top level, and reports the context size before and after. Earlier messages stay in the session history.- Codemode
store(key, value)andload(key)keep JSON values across scripts in a conversation, as in Pi. Values survive a restart, a thread started from a run sees the values as of that run, and/newclears them.
Upgrade steps
- Run
mikan migrateafter upgrading. The new step0013-session-usagerecords the spend of sessions imported from 0.5.3 in pi-durable's usage ledger; the daemon does not start while it is pending. - Existing Slack apps must add
/pi-compactto their slash commands. The example manifests include it.
Notable changes
- MCP tool results reach the model through pi-mcp's
toLlmContent, so an image embedded as a resource is passed to the model as an image. - Slack DM tasks are found, and their status and acknowledgement read, from pi-durable's task records instead of
log.jsonl, so task status keeps working after a lost or rotated log. Task threads started before 1.1.0 are no longer recognized as tasks, and tasks started from 1.1.0 to 1.2.2 list without their acknowledgement.
Fixes
- The Admin portal's usage views count each session's own spend: a thread started from the run that caused it no longer repeats its parent's spend. Totals now include failed attempts and compaction.
/newin a DM no longer waits for running background tasks or other DM threads (#158).
Verification
- CI and the Slack E2E workflow pass for each change.
- Each change was checked with an acceptance eval against the previous
main, and on a local Slack daemon.
See CHANGELOG.md for details.
1.2.2
What's changed
Notable changes
jev_browserwrites the text it types or selects with the conversation's chat model, the one the office'ssettings.jsonresolves, through pi-ai, instead ofopenai/gpt-4o-minicalled directly on OpenRouter. It no longer needsOPENROUTER_API_KEYand follows the office's provider. Jev still chooses each step; it only classifies, so it cannot write the text itself.
With 1.2.1's built-in provider override for Jev, mikan no longer needs an OpenRouter key unless an office's chat model or Jev runs on OpenRouter.
Verification
- CI and the Slack E2E workflow pass.
- On a local Slack daemon started without
OPENROUTER_API_KEY,jev_browserfilled a form's name field with text written by the office model while Jev went through amodels.jsonproxy.
See CHANGELOG.md for details.
1.2.1
What's changed
Highlights
-
Jev on any provider Pi ships it with. Jev uses the first of pi-ai's built-in Jev models whose provider has a key: OpenRouter, TypeSafe, Vercel AI Gateway, Cloudflare Workers AI, then OpenCode. A deployment with only
TYPESAFE_API_KEY, for example, now has Jev. -
Jev through a proxy, the Pi way. A
models.jsonentry that gives a built-in provider only abaseUrland anapiKey, as Pi documents for proxies, now also redirects that provider's classifier models and uses that key. Jev reads the daemon'smodels.json, so this sends Jev through a System One gateway without an OpenRouter key:{ "providers": { "typesafe": { "baseUrl": "https://llm-gateway.example.com/v1", "apiKey": "<gateway key>" } } }
Upgrade notes
- The
jevsetting and the"type": "classifier"models inmodels.jsonthat 1.2.0 added are removed, because Pi'smodels.jsonhas no such fields. If you used them, switch to the built-in provider override above. jev_browseragain writes form text withopenai/gpt-4o-minion OpenRouter, as in 1.1.0, so it still needsOPENROUTER_API_KEY.
Verification
- CI and the Slack E2E workflow pass.
- On a local Slack daemon started without
OPENROUTER_API_KEY, withmodels.jsonsetting onlytypesafe.baseUrlandtypesafe.apiKeyto a local System One relay, thejevtool and the Memory capture gate reached Jev through the relay with that key.
See CHANGELOG.md for details.