CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
All notable changes to this project will be documented in this file.
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
from 1.0.0 on. The package interface is the root export of `@geminixiang/mikan`; the
CLI, `settings.json`, `mikan.env`, and the state layout under `~/.mikan` are covered too.
The GitHub adapter is experimental and excluded: its settings and conversation layout may
change in a minor release.
## [Unreleased]
## [2.0.0-beta.0] - 2026-11-11
Back up the state directory (`~/.mikan`) before upgrading: once this version opens it, an earlier
version cannot.
### Added
- In a Slack channel, the model can hand long work to a background task, as it already could in a
direct message: mikan acknowledges at the top level and works in that message's thread, and other
mentions in the channel are answered meanwhile. A mention in the task thread asks for status or,
from the requester, steers the task.
- `read` resizes and converts images it could not return before: those over 2000x2000 pixels or
4.5 MB, and formats such as BMP.
### Changed
- Upgraded Pi to 1.5.2, with all Pi packages pinned to that exact version. Pi migrates the state
directory's storage on first start, which is what makes the upgrade one-way. A crash now loses up
to one second of streamed text instead of 100 ms, and a task cut off five times in a row ends with
a failure instead of staying busy.
- The model browses with the `agent-browser` CLI through `bash`. The `jev_browser` tool is removed,
and with it the desktop page's "Take control" and hand-back; the desktop still shows the sandbox.
- Each firing of a scheduled event on Telegram and Discord runs in a new session, as on Slack.
Before, a periodic event carried every earlier run in its context.
- Codemode and `tool_search` are Pi's. A script survives a restart without rerunning the calls it
finished, and `bash` resolves to `{ output, exitCode }` inside a script.
- Model spend by the `jev` tool counts toward session usage and budgets.
### Removed
- The `subagent` tool, its profiles in `<workspace>/agents/*.md`, and its progress dashboard
(ADR 0028). A conversation does the work itself; Slack keeps background tasks for long work.
- Memory capture, which rewrote `MEMORY.md` after a run (ADR 0029). The agent updates `MEMORY.md`
itself during a run. Lines captured earlier stay as they are.
- The tool loop guard, which appended a notice after repeated identical tool calls.
- For embedders: `ConversationRuntimeOptions.memoryCapture`, `CreateRunnerOptions.desktop`,
`ConversationResponder.respondToolResult`, and the `ChatToolResult` type. Delete the option or
method where you pass it.
### Fixed
- `/pi-login` typed as a slash command in a Slack channel opened a link to the channel's shared
vault while calling it "your vault". It now refuses and asks for a direct message, as documented.
- A run that produced messages faster than the platform could show them lost some of them.
- After a restart, a tool call that was running is shown again with its arguments.
- Requests to OpenRouter no longer name Pi as the calling app.
## [1.5.2] - 2026-11-11
### Fixed
- A clean install of 1.5.1 failed to start, because its Pi packages were declared as version ranges
and a later Pi minor release removed exports mikan imports. The Pi packages are now pinned to the
exact versions 1.5.1 was tested with. Nothing else changes.
## [1.5.1] - 2026-10-14
### Changed
- A Slack reply or task that a restart interrupts now continues after the restart instead of
stopping with its progress message stuck: mikan posts "Restarted for an update; continuing." and
pi-durable continues the same turn, telling the model which step was interrupted. A deploy no
longer waits up to five minutes for Slack runs to finish. Tasks continue the same way, without the
earlier limit of two automatic resumes. Other platforms keep the five-minute drain.
- A codemode script has no deadline unless it sets `timeout_ms`, as in Pi. Before, mikan stopped
every script after 60 seconds, which cut off scripts that call slow tools such as
`jev_browser`'s goal loop. A stuck script now runs until the conversation is stopped, or until
the run's budget ends it where one is set, as for scheduled events.
- `jev_browser` with only `url` opens the page and returns its final URL and title, for example to
show it on the office desktop. Before, it refused the call, and models made up a goal that ran the
slower goal loop.
### Fixed
- `jev_browser` no longer refuses a call because the model filled `handOff` with an empty string,
as models that fill every optional field do; an empty `handOff` and `frame: "main"` count as not
given.
## [1.5.0] - 2026-10-13
### Added
- `/pi-desktop` (`/desktop` on other platforms) sends a private 24-hour link to the conversation's
desktop in the managed `oci` sandbox: 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 with `jev_browser`'s `handOff`, 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 from stopping while someone has it open. It needs the sandbox image of
this release; an office whose sandbox still runs an older image gets it after the sandbox idles out.
Register `/pi-desktop` in the Slack app manifest, or let mikan do it (next entry).
- mikan creates and updates its Slack app (ADR 0026). With a Slack app configuration token,
`mikan onboard` creates the app from mikan's manifest, and 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. Store a token for an existing app with `mikan slack token`, and
set the app's and bot's name and the description with `mikan slack set`. Settings added by hand in Slack are
removed. When a release adds a scope, mikan DMs the token's owner a reinstall link. Without a
token nothing changes.
### Changed
- `jev_browser` closes only tabs it opened when it passes its three-tab limit, so tabs a person
opened stay open.
- The sandbox image adds `sway`, `wayvnc`, and `foot` (about 1 MB) and the `mikan-desktop` script.
- Upgraded Pi to 1.2.0. Pi 1.2 removed an export mikan 1.4.0 imports, so a fresh install of 1.4.0
now fails to start; this release works with it. A nonzero `bash` exit is now an error result that
carries the output and the exit code, instead of a thrown error.
### Removed
- The Slack App Home tab, which listed running tasks and scheduled jobs with force-stop buttons.
mikan's Slack manifest turns the tab off; an app synced from a configuration token loses it on
the next start, and an app configured by hand keeps showing 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.
## [1.4.0] - 2026-10-11
### Added
- `web_fetch` reads a public web page or API from the host so the agent can check versions,
releases, and dates against the official source instead of answering from memory. HTML is
returned as Markdown without navigation; long results are bounded like MCP results, with the
full text saved in the workspace. It needs no key and refuses private, loopback, and link-local
addresses, including through redirects. It does not go through an HTTP proxy configured for
the daemon.
- The OCI sandbox runs on nerdctl, Podman, or Docker. mikan uses the first engine whose `info`
succeeds, in that order, and logs its choice; set `CONTAINER_ENGINE` to pin one.
- `--sandbox=oci` without an image uses `ghcr.io/geminixiang/mikan-sandbox:<mikan version>`, so
the sandbox image upgrades and rolls back with mikan. At startup mikan pulls the configured
image in the background; a failed pull logs a warning and offices keep the local image. A
stopped office's container is replaced when its image changed. After any replacement, the
previous image is removed once no container uses it; an image that still has another name is
kept. A running container is never replaced.
### Changed
- `--sandbox=image:<image>` is now `--sandbox=oci:<image>`. `image:` still works, prints a
deprecation warning, and will be removed in the next major release; existing containers and
vaults are kept. `mikan onboard` and the PM2 template write `--sandbox=oci`.
- Container tools run through Pi's `pi-env` daemon over one connection per container, instead of
one engine `exec` per operation: file operations and commands take about 1 ms instead of
40–180 ms, and commands end as soon as mikan disconnects. String commands run with `bash` when
the container has it, and oversized command output is saved in the container's temporary
directory.
- Each office with a running container keeps one `<engine> exec -i` client process on the host,
the connection to its `pi-env` daemon. Commands left by a version before this one are no longer
swept at startup; they end when their container stops or is replaced.
- Each container gets the mikan host's time zone. The sandbox image no longer sets
`TZ=Asia/Taipei` and is about 390 MB smaller: `vim`, `nano`, `less`, `bash-completion`,
`python3-venv`, `gnupg`, and gcloud's precompiled Python files are gone.
- Existing containers are recreated once on first use after upgrading, because mikan now
identifies a container's network and image by labels it writes at creation. Workspace and vault
mounts are kept; packages installed inside the container are not. On a host running more than
one engine, mikan may pick a different engine and create new containers there; set
`CONTAINER_ENGINE=docker` to keep Docker.
### Security
- With a vault resolver, a conversation has no execution environment until its first run resolves
one, so a tool call that arrives earlier fails instead of running on the host.
- Container credentials reach the sandbox through the `pi-env` connection instead of command
arguments or a host-side env file.
## [1.3.0] - 2026-10-10
### Added
- `/compact [instructions]` (`/pi-compact` in 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. Existing Slack apps
must add `/pi-compact` to their slash commands; the example manifests include it.
- Codemode `store(key, value)` and `load(key)` keep JSON values across scripts in a conversation,
as in Pi, instead of only within one script. Values survive a restart, a thread started from a
run sees the values as of that run, and `/new` clears them. They are kept in a pi-durable
document of the conversation.
### Changed
- 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 instead of a placeholder line; other resource,
link, and audio placeholders use pi-mcp's wording.
- `mikan migrate` has a new step, `0013-session-usage`, that records the spend of sessions
imported from 0.5.3 in pi-durable's usage ledger. Run `mikan migrate` after upgrading; the
daemon does not start while the step is pending.
- Slack DM tasks are found, and their status and acknowledgement read, from pi-durable's task
records instead of `log.jsonl`, so `task_status` and the in-thread status reply keep working
after a restart with a lost or rotated log, and a status reply in a task thread no longer scans
the log for task roots (0.5 s to 0.14 s with a 50 MB 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.
### Fixed
- The Admin portal's usage views count each session's own spend: a thread started from the run
that caused it no longer repeats the spend of the conversation it was started from. Session
totals come from pi-durable's usage ledger, so they now include failed attempts and compaction.
- `/new` in a DM no longer waits for running background tasks or other DM threads, and
messages sent after it no longer wait with them; it resets its own session as soon as that
session is idle ([#158](https://github.com/geminixiang/mikan/issues/158)).
## [1.2.2] - 2026-10-09
### Changed
- `jev_browser` writes the text it types or selects with the conversation's chat model, the one
the office's `settings.json` resolves, instead of `openai/gpt-4o-mini` called directly on
OpenRouter, so it no longer needs `OPENROUTER_API_KEY` and follows the office's provider.
## [1.2.1] - 2026-10-09
### Added
- Jev uses the first of pi-ai's built-in Jev models whose provider has a key, starting with
OpenRouter and then TypeSafe, Vercel AI Gateway, Cloudflare Workers AI, and OpenCode, so it
works with `TYPESAFE_API_KEY` and the other providers Pi lists, not only `OPENROUTER_API_KEY`.
- A `models.json` entry that gives a built-in provider only a `baseUrl` and an `apiKey`, as Pi
documents for proxies, now also redirects that provider's classifier models and uses that key.
Jev reads the daemon's `models.json`, so `"typesafe": { "baseUrl": …, "apiKey": … }` sends Jev
through a System One proxy without an OpenRouter key.
### Removed
- The `jev` setting and the `models.json` classifier models added in 1.2.0 are removed, so
`models.json` follows Pi's format again. To send Jev through a gateway, use the built-in
provider override above. `jev_browser` again writes form text with `openai/gpt-4o-mini` on
OpenRouter, as in 1.1.0, so it still needs `OPENROUTER_API_KEY`.
## [1.2.0] - 2026-10-09
### Added
- Jev can run on any service that speaks TypeSafe's System One protocol, such as an LLM gateway.
Set `jev` in `settings.json` to a provider and model, and declare that model in `models.json`
with `"type": "classifier"` and `"api": "typesafe-system-one"`; mikan sends it to
`<baseUrl>/systemone` with the provider's key. Without the setting Jev stays on OpenRouter.
### Changed
- `jev_browser` writes text for form fields with the conversation's chat model instead of
`openai/gpt-4o-mini` on OpenRouter, so it no longer needs `OPENROUTER_API_KEY`.
- Jev decisions go through pi-ai's classifier support instead of `@geminixiang/jev`, which is
removed. The model, `OPENROUTER_API_KEY`, timeout, and retries stay the same; requests go to
OpenRouter's System One endpoint, a text state is sent as `{ "text": … }`, score answers no
longer carry per-level probabilities, and cost is the token count at pi-ai's catalog price.
- A periodic event run always posts its answer. The `[SILENT]` reply that deleted the message
is removed, along with the prompt rules that told the agent to use it or to react with eyes
instead of reporting nothing new, because a job that kept answering `[SILENT]` could stall for
days without anyone noticing. An event whose own text still asks for `[SILENT]` now posts that
text; edit the event to say what it should report instead.
### Fixed
- A DM task resumes after a restart at most twice in a row. Before, a task whose step crashed
the daemon was resumed on every restart for up to 24 hours, crashing it again each time; now
the third interruption stops the task and says so once in its thread.
- A scheduled event's reply no longer ends with two signatures. The system prompt told the agent
that event messages start with an `[EVENT:<file>:…]` prefix, which events stopped carrying in
May, so the agent signed the reply as `[event: unknown]` and mikan added the real signature.
An event run is now told its event file in the Event Trigger Mode instructions, and a message
that starts with a typed `[EVENT:` marker is no longer attributed to an event.
## [1.1.0] - 2026-10-08
### Added
- A DM task survives a restart. A deploy no longer waits up to five minutes for running
tasks, and a task interrupted by a deploy or crash in the last 24 hours resumes in its
thread with a notice. A stopped task stays stopped.
- A finished task's answer is written to the DM conversation that started it, so a later
question in the DM can be answered from the result.
### Changed
- Pi packages are upgraded to 1.1.0. Retryable "server busy" provider errors are retried, the
first system prompt leads the model context so tool changes keep the prompt cache, and
each tool result records how long it ran. The container sandbox implements Pi's new file
reader in one `docker exec` per read, as before.
- Embedders: `ConversationResponder` no longer has `appendResponseDelta` or
`finishResponse`. `replaceResponse` always receives the whole main message, with
`{ final: true }` on the final write, and a responder sets `showsPartialAnswer` to receive
the answer while it is written. A responder that implemented the removed methods stops
receiving streamed text until it handles `replaceResponse` this way.
### Fixed
- A task run is no longer offered `task_status` and `start_task`, which made one of three
test tasks report its own status instead of doing the work.
- A reply's message no longer flickers between its text and the tool checklist. Text written
before a tool call stays under the checklist until the next answer replaces it, the
message is updated at most once a second, and the final answer is written once instead of
three times. A Slack thread reply that has to change earlier text stops streaming and is
edited in place instead of deleted and posted again.
- The `...` that marks a reply still being written is removed when the reply ends, also when
the final edit is first rejected.
- A signature the model wrote at the end of its last line is replaced, so a reply no longer
ends with two `Triggered by` lines.
- A reply no longer streams with its first words missing. The first text of an answer, and
sometimes its last, never reached the chat while it streamed, so the message jumped when
the final version replaced it, and a Slack thread reply was deleted and posted again.
## [1.0.2] - 2026-10-08
### Changed
- The system prompt lists the folders already in the office's `scratch/` and asks the agent
to reuse an existing clone, with `git fetch` or `git worktree add`, before cloning again.
A new thread previously could not tell a repository was already there and cloned another copy.
### Fixed
- A command left running in a container sandbox by a crashed or killed daemon is ended
when the daemon starts again, so a resumed or repeated run does not race the old copy.
## [1.0.1] - 2026-10-07
### Changed
- `mikan onboard` asks for a sandbox image instead of a sandbox mode: the published
`mikan-sandbox` image (recommended), `debian:trixie-slim`, or any other image. It writes
`~/.mikan/ecosystem.config.cjs` with that image and prints the `docker pull` and
`pm2 start` commands, so the PM2 file no longer has to be downloaded. An existing
ecosystem file is kept. `host` and `container:<name>` still work through `--sandbox` but
are no longer offered.
- The README and the quick start and deployment guides, in all four languages, follow the
onboard flow: install, `mikan onboard`, `docker pull`, and `pm2 start` with the generated
ecosystem file. The docs site has a new logo, favicon, hero image, and footer.
### Fixed
- Stopping a run, or a command timing out, now ends the command inside the container
sandbox. Before, only the host `docker exec` client was killed and the command kept
running in the container. Images without `setsid` keep the old behavior.
## [1.0.0] - 2026-10-06
1.0.0 is the first stable release. It replaces the 0.5.3 runtime, which ran on
`pi-coding-agent`, with mikan's own harness on `pi-durable` and `pi-ai`, and gives every
conversation its own office. The 97 `1.0.0-beta.*` prereleases are summarized here; their
individual notes remain in the [GitHub releases](https://github.com/geminixiang/mikan/releases).
### Upgrading from 0.5.3
`mikan migrate` upgrades a 0.5.3 install in place; it is the only supported upgrade path, and
formats that existed only in 1.0.0 prereleases are not converted. The daemon refuses to start
while migrations are pending and prints the exact command to run. Follow
[Upgrading from 0.5.3](https://mikan.geminixiang.com/deployment/#upgrading-from-053) in the
deployment guide, which lists what migrates, what does not, and what to check afterwards.
### Added
- **Conversation offices.** Each conversation gets its own directory, sandbox runtime, vault,
settings, sessions, and scheduled events, named by an office key
(`v1-<platform>-<readable-id>-<hash>`) so two platforms never collide on one raw id. Offices
are public or private, following the Slack conversation type, and `image:*` sandboxes enforce
it: a private office sees only itself plus shared knowledge. `mikan office list` prints them.
- **GitHub adapter (experimental).** A regular GitHub account, bound with a fine-grained token and an
organization webhook, answers mentions, assignments, and review requests; each issue or pull
request is one conversation. Its settings and conversation layout may change in a minor
release, and conversations from this version may not carry over.
- **Durable sessions.** Each office keeps its sessions in one SQLite database (`sessions.db`)
through `pi-durable`. Sessions survive restarts, a channel's top-level session stays current
until `/new` with Pi compacting old context, and threads keep their own sessions. The agent's
`history` tool reads the conversation's earlier sessions.
- **MCP servers and codemode.** `mcpServers` in `settings.json` connects MCP servers; the agent
reaches their tools through Pi's codemode and searches large tool lists on demand.
OpenConnector can provision a per-conversation MCP token.
- **Subagents.** The agent delegates bounded work, in parallel or as a dependency graph, to
subagents with role profiles, their own tools, and token, cost, and time budgets.
- **Admin portal and session viewer.** `/admin` opens a 30-minute portal for model, sandbox
limits, office visibility, reply mode, MCP servers, and skills; `session` opens a read-only view
of the current session.
- **Memory capture.** After each human-triggered run, durable facts go to the office's
`MEMORY.md`.
- **Jev.** A small model answers yes/no decisions, such as whether a Slack message addresses the
bot in `/pi-auto-reply jev` mode, and drives the `jev_browser` tool.
- **Platform rendering.** Slack answers stream into native markdown and table blocks, with the
`slack_blockkit` tool for interactive messages; Discord uses Components V2; Telegram uses rich
formatting. Long answers continue in the thread instead of failing.
- **CLI.** `mikan onboard` writes `settings.json` and `mikan.env` from a few questions, `mikan env`
lists every environment variable and which are set, and `mikan migrate` applies state
migrations with `--dry-run`.
- **Observability.** Standard OTLP export through the `OTEL_*` variables, alongside Sentry.
### Changed
- Node.js 24.15.0 or newer is required.
- `mikan.env` holds secrets and deployment addresses; `settings.json` holds behavior. The
Sentry DSN is read only from `SENTRY_DSN`, so a `sentry.dsn` setting is ignored, and the GitHub
adapter's repositories and trigger rules live under `github` in `settings.json`. At startup the
daemon logs each environment variable it no longer reads, with what replaces it.
- State lives in `~/.mikan` only: `settings.json`, `mikan.env`, `models.json`, vaults, and the
host-only per-conversation directories under `conversations/`. Per-conversation settings,
sessions, and scheduled events moved out of the workspace, where sandboxes could read them.
- The workspace argument is optional and defaults to `~/.mikan/workspace`.
- Inside a sandbox, an office's files are at `/workspace/<office-key>` instead of
`/workspace/<conversation-id>`. Paths quoted in sessions from before the upgrade point at the
old location.
- `image:<image>` provisions one managed container and one vault per office, recreated from the
current image when missing; `/pi-sandbox boost` raises its limits until it stops.
- Vault directories use hashed keys instead of raw user and container names.
- Only `session` and `stop` work without a leading slash; `new`, `model`, and `auto-reply` need
their slash forms (`/new`, `/pi-new`, …).
- Auto-reply is Slack-only and takes `on`, `off`, or `jev`. A 0.5.3 channel with auto-reply
rules replies to every top-level message; the rules are ignored.
- The link server for the portal and credential links listens on `127.0.0.1` unless
configured otherwise.
- The package exports only what an embedder needs: `createConversationRuntime`,
`createWorkspace`, `createOfficeAddress`, `officeKey`, `createConversationEvent`,
`createConversationMessage`, `defaultCommandHandlers`, `MikanModels`, and the types they use.
The `@geminixiang/mikan/harness` and `@geminixiang/mikan/sandbox` entry points are gone.
### Removed
- The `pi-coding-agent` runtime and its extension loading; mikan loads no third-party code into
its process (ADR 0006). Skills in `skills/` directories remain.
- The `firecracker:*` and `cloudflare:*` sandboxes.
- `--state-dir` and the `STATE_DIR` / `MIKAN_STATE_DIR` variables, and `--download`.
- Auto-reply on Discord and Telegram, and auto-reply rules.
- `SENTRY_ENABLED` (leave `SENTRY_DSN` unset to turn Sentry off) and `HTTP_IDLE_TIMEOUT`
(outbound HTTP streams time out after five minutes).
- Provider keys in `~/.pi/mikan/auth.json`; put them in `~/.mikan/mikan.env` or `models.json`.
### Fixed
- Slack startup and reconnects no longer hang without a log line when Slack accepts the
connection and never answers; a socket silent for 30 seconds is dropped and retried, and the
daemon logs `Slack connection lost; reconnecting` and `Slack reconnected after Ns`.
- Stopping the daemon while it is still connecting to Slack ends in a graceful shutdown.
- When Telegram ends long polling because the token was revoked (401) or another process polls
the same bot (409), the daemon logs the reason and exits with code 1 for the process manager
to restart, instead of running on without receiving messages.
- A Slack message whose acknowledgement was lost during a reconnect runs once, not twice.
## [0.5.3] - 2026-06-30
### Added
- Append a session-view link to event-triggered attribution messages.
- Show raw cached token counts and cache-hit rate in usage summaries.
### Changed
- Use a stable, low-noise usage summary layout with token units and fixed cost breakdowns.
- Mark the auto-reply command as deprecated.
### Fixed
- Harden state file writes to avoid readers seeing partial state.
- Reject malformed OAuth configuration during login setup.
### Tests
- Add unit coverage for utility and tool modules.
- Expand Slack end-to-end coverage and make CI Slack artifacts more reliable.
## [0.5.2] - 2026-06-26
### Added
- Show the top 20 pi sessions by token usage in the admin portal, including channel labels and raw input, output, cache read, cache write, total, and cost columns.
## [0.5.1] - 2026-06-26
### Added
- Render markdown as Slack Block Kit.
- Show live tool progress during agent runs.
## [0.5.0] - 2026-06-25
### Added
- Add the Starlight documentation site with localized docs for English, Japanese, Simplified Chinese, and Traditional Chinese.
- Add platform adapter guides for Slack, Discord, and Telegram.
- Add a web agent-events portal for streaming agent events.
### Changed
- Align adapter, runtime, and session naming around conversation terminology for clearer contributor navigation.
- Update project dependencies and bundled pi packages.
### Fixed
- Preserve custom Starlight theme component overrides.
- Keep the docs dev server from restarting when settings cleanup runs.
- Tighten Sentry event sanitization.
## [0.4.8] - 2026-06-22
### Changed
- Update bundled pi packages to the 0.79.9 line.
## [0.4.7] - 2026-06-22
### Fixed
- Apply the recent-days and max-messages history window when syncing existing chat sessions so resuming a session no longer replays unbounded older log history.
### Changed
- Always report a usage summary whenever token usage is available.
### Tests
- Add coverage for capping existing chat history sync to the recent history window.
## [0.4.6] - 2026-06-18
### Fixed
- Store Slack streamed responses as a single finalized bot log entry instead of per-delta fragments.
- Coalesce legacy Slack bot log fragments when bootstrapping chat sessions so platform history is not filled with partial words.
### Tests
- Add coverage for coalescing streamed bot history and logging only finalized Slack responses.
## [0.4.5] - 2026-06-17
### Added
- Rotate shared top-level channel sessions on biweekly Sunday boundaries while keeping thread sessions fixed.
### Changed
- Bootstrap rotated shared channel sessions from the recent two-week chat log window and prevent older log history from being resynced into the active session.
- Harden managed Docker sandboxes with dropped capabilities, no-new-privileges, and a PID limit.
### Fixed
- Report usage summaries when token usage is available even if provider pricing data is missing.
### Tests
- Add coverage for session rotation, thread bootstrap watermarks, sandbox hardening flags, and usage summaries without cost data.
## [0.4.4] - 2026-06-12
### Fixed
- Require exact provider model ID matches when grouping verified admin model availability.
## [0.4.3] - 2026-06-12
### Added
- Group admin model selectors by verified availability for OpenAI and Anthropic keys.
- Log the active provider and model when each agent run starts to simplify server-side debugging.
## [0.4.2] - 2026-06-11
### Fixed
- Resolve custom providers through pi's model registry so conversation settings can select models from `models.json`.
- Resolve attached file paths from the sandbox runtime workspace so image sandboxes upload generated files from the correct host path.
## [0.4.1] - 2026-06-08
### Changed
- Update bundled pi packages to the 0.78.1 line.
### Fixed
- Stream Slack responses with delta-only appends to avoid duplicated message segments and streaming state conflicts.
- Include Slack streaming recipient metadata so threaded streamed replies work in Slack E2E and production workspaces.
### Tests
- Add Slack streaming E2E coverage for delta appends without duplicate text.
## [0.4.0] - 2026-06-07
### Added
- Add streamed response deltas across adapters so replies can update progressively.
- Add Slack reply mode configuration in the admin portal.
- Add event tool CRUD support for listing, reading, updating, and deleting scheduled events, with conversation-scoped listing by default and explicit all-event listing.
### Changed
- Reorganize source modules and centralize shared type definitions for clearer contributor navigation.
- Centralize adapter conversation intake and reduce wrapper indirection across runtime, adapters, commands, config, and web modules.
- Attribute agent Sentry traces with platform and conversation context for clearer operator debugging.
### Fixed
- Persist global settings overrides correctly.
- Warn when invalid custom OAuth service definitions are skipped instead of silently dropping them.
## [0.4.0-beta.0]
### Added
- Add streamed response deltas across adapters so replies can update progressively.
- Add Slack reply mode configuration in the admin portal.
- Add event tool CRUD support for listing, reading, updating, and deleting scheduled events, with conversation-scoped listing by default and explicit all-event listing.
### Changed
- Reorganize source modules and centralize shared type definitions for clearer contributor navigation.
- Centralize adapter conversation intake and reduce wrapper indirection across runtime, adapters, commands, config, and web modules.
### Fixed
- Persist global settings overrides correctly.
## [0.3.2] - 2026-06-02
### Fixed
- Preserve trigger attribution in streamed agent responses so tool-written GitHub comments include the triggering user.
## [0.3.1] - 2026-06-02
### Added
- Add Slack Block Kit response support and document Block Kit implementation lessons.
### Fixed
- Require explicit mentions before Slack thread replies trigger the bot.
### Tests
- Enforce phase-one strict checks and unused export checks.
## [0.3.0] - 2026-06-01
### Added
- Add source directory README guides for contributors navigating adapters, commands, runtime, sessions, sandbox, tools, login, admin, and session-view code.
### Changed
- Centralize chat session bootstrapping through `ChatSessionManager` so Slack top-level and thread sessions share the same log-based history sync path.
- Rename Slack branch/fork terminology to thread/anchor terminology across the adapter, session viewer, and documentation.
- Model session-view related sessions as parent/thread relationships, including fixed-path thread sessions without legacy parent metadata.
- Remove legacy thread fork and snapshot helpers from session storage.
### Fixed
- Anchor session-view thread links on the root turn instead of earlier bootstrapped context messages.
## [0.3.0-beta.0]
### Changed
- Centralize chat session bootstrapping through `ChatSessionManager` so Slack top-level and thread sessions share the same log-based history sync path.
- Rename Slack branch/fork terminology to thread/anchor terminology across the adapter, session viewer, and documentation.
- Model session-view related sessions as parent/thread relationships, including fixed-path thread sessions without legacy parent metadata.
- Remove legacy thread fork and snapshot helpers from session storage.
### Fixed
- Anchor session-view thread links on the root turn instead of earlier bootstrapped context messages.
## [0.2.4] - 2026-06-01
### Fixed
- Make Slack bot-rooted thread session seeds loadable by storing platform-history assistant metadata.
## [0.2.3] - 2026-06-01
### Added
- Add a sandbox resource limit tool for checking and temporarily updating managed sandbox CPU and memory limits.
### Fixed
- Isolate Slack sessions rooted at bot messages so thread replies do not inherit unrelated channel history.
## [0.2.2] - 2026-05-30
### Added
- Add `/admin` portal with token-protected access via `/admin` and `/pi-admin` commands.
- Add admin APIs and UI for conversation settings, global settings, workspace preview, skills, events, session links, and login/vault links.
- Add model selection in the admin portal using `ModelRegistry.getAvailable()` instead of free-text fields.
- Share portal shell chrome across admin, session-view, and login/vault pages.
- Document admin, login, and session token boundaries in `docs/portal-auth-model.md`.
### Changed
- Normalize slash-command feedback into muted compact summaries.
- Align desktop layout widths across all portal surfaces.
## [0.2.1] - 2026-05-27
### Added
- Add expanded command, configuration, deployment, development, session, and skill documentation.
- Add README hero and architecture diagrams.
- Add project agent development rules and Karpathy coding guidelines.
### Changed
- Simplify the README overview and clarify sandbox runtime architecture documentation.
- Simplify file guards and retry helpers.
### Fixed
- Retry attachment downloads.
- Skip retry sleep on the final attempt and clarify retry naming.
## [0.2.0] - 2026-05-23
### Changed
- Renamed the project, CLI, npm package, GitHub repository, documentation, release skill, and sandbox image references to mikan.
- Changed platform credentials to unprefixed env vars (`SLACK_APP_TOKEN`, `SLACK_BOT_TOKEN`, `TELEGRAM_BOT_TOKEN`, `DISCORD_BOT_TOKEN`) while keeping `MIKAN_*` aliases as fallbacks.
- Changed runtime env vars such as `LINK_URL`, `LINK_PORT`, `STATE_DIR`, OAuth scope overrides, and Cloudflare sandbox settings to prefer unprefixed names with `MIKAN_*` fallbacks.
- Raised the minimum supported Node.js version to `>=22.19.0`.
- Updated internal variable, function, type, Docker label, sandbox image, and generated resource names to use mikan naming.
- Added manual dispatch support to the CI workflow.
## [0.2.0-beta.25] - 2026-05-23
### Changed
- Grouped session modules under a single directory.
- Centralized command parsing across adapters.
- Removed explicit `any` usage across the type surface.
- Cleaned unused dependencies.
### Tests
- CI now enforces coverage thresholds.
## [0.2.0-beta.24]
### Fixed
- Session history writes now emit valid assistant messages.
## [0.2.0-beta.23]
### Fixed
- Refresh stale channel history before forking a thread.
- Separate history seeds from live sessions to prevent cross-contamination.
- Materialize channel history when the first thread is created.
### Added
- Scripts to migrate session history and repair orphan thread sessions.
## [0.2.0-beta.22]
### Fixed
- Slack: fork bot response threads from the channel session so replies inherit context.
- Vault: preserve failures when the default shared vault cannot be applied.
## [0.2.0-beta.21]
### Added
- Vault: seed new sandboxes from a shared profile (`sandbox.defaultSharedVault`).
## [0.2.0-beta.20]
### Added
- Sentry: report user-facing failures.
- Auto-reply: surface configured rules in the status command.
### Fixed
- Slack: anchor event-fork sessions correctly (#61).
- Slack: keep session ephemerals scoped to threads.
- Agent: require history search before answering unknown replies.
- Agent: keep quiet tool errors out of chat.
### Changed
- Removed cloud-logging config — log to stdout/stderr and route via your process manager.
## [0.2.0-beta.19]
### Fixed
- Sandbox: bootstrap `gh` git credentials inside managed containers.
## [0.2.0-beta.18]
### Fixed
- Sandbox: update memory swap when applying CPU/memory limits.
- Slack: preserve long replies posted in threads.
## [0.2.0-beta.17]
### Added
- Sentry: store env values and write a `sentry-cli` config for richer error reports.
### Changed
- Bumped `@earendil-works/pi-*` packages.
## [0.2.0-beta.16]
### Performance
- Slack: unblock startup while backfill is running.
## [0.2.0-beta.15]
### Added
- Config: validate JSON files with TypeBox schemas.
- Agent: attribute the trigger (mention/direct/auto-reply/…) in responses.
## [0.2.0-beta.14]
### Fixed
- Login: refresh the sandbox after copying a shared profile.
### Changed
- Simplified command dispatch, token stores, and re-exports (#60).
## [0.2.0-beta.13]
### Added
- Login: gcloud OAuth support.
## [0.2.0-beta.12]
### Fixed
- Auto-reply: persist the resolved session key.
## [0.2.0-beta.11]
### Fixed
- Login: make Slack login ephemeral and refresh vault mounts after credentials change.
### Changed
- Sandbox: update base image and tags.
## [0.2.0-beta.10]
### Added
- Auto-reply: channel trigger rules and a configurable judge model (`llm.autoReply`).
- Slack: native E2E smoke workflow under `e2e/`.
### Fixed
- Auto-reply: use mom-compatible marker files; judge policy never throws and always logs.
- Events: validate one-shot times before scheduling; simplify fresh follow-up sessions.
### Changed
- Onboard: default model is `claude-sonnet-4-6`.
- Separated runtime and control-plane paths.
## [0.2.0-beta.9]
### Added
- Session view: floating composer and per-message copy button.
- Docker sandbox: add `rg` and `fd` to the image.
### Fixed
- Session view: ignore Enter during IME composition; preserve code-block contrast.
## [0.2.0-beta.8]
### Added
- Login: shared vault profiles.
- Session view: improved interactive chat console.
- Slack: harden socket connection and label the platform in the connect log.
- Agent: `ThinkingLevel` type on session parameters.
### Changed
- Sandbox: store the image workspace mount in settings.
- Dropped `vault.json` metadata — directories are the only source of truth.
- Refactored agent runner orchestration into smaller modules.
### Removed
- `UserBindingStore` and `bindings.json` plumbing.
- Log-to-session backfill.
## [0.2.0-beta.7]
### Added
- Sandbox: temporary `boost` command for one-off CPU/memory bumps.
- Slack: mute command summaries.
### Changed
- Migrated `pi-*` packages to the `@earendil-works/` namespace.
### Fixed
- Slack: log messages from external apps; hide bash tool diagnostics.
- Session: ignore history written before a reset.
- Agent: clarify runtime workspace paths in the system prompt.
## [0.2.0-beta.6]
### Added
- Commands: conversation model switch (`/pi-model …`) with `:thinking` shorthand.
- Config: onboarding flow for global settings (`mikan --onboard`).
- Docs: PM2 ecosystem config and production deploy guide.
### Changed
- Config: nest settings schema; align chat platform commands.
### Fixed
- Slack: strip only the bot's own mention from message text.
## [0.2.0-beta.5]
### Added
- Sandbox: Cloudflare sandbox bridge (experimental).
- Tests: unit coverage for `CommandRegistry` and command handlers.
### Changed
- Env: renamed `MOM_*` env vars to `MIKAN_*` (breaking).
- Vault: conversation vault directories are now the source of truth; dropped platform prefix from the conversation vault key.
- Config: `--state-dir` is the single source for settings.
- Tightened command/runtime types and added a `postPrivate` capability.
## [0.2.0-beta.4]
### Changed
- Hardened core writes; unified adapter retry and log helpers.
- Eliminated duplication across adapters, vault, and Slack command factories (#53).
- Session forks now anchor to raw split points.
- Adapter-specific stop logic stays in adapters.
### Fixed
- Slack: tighten thread reply triggers.
## [0.2.0-beta.3]
### Added
- Session view: Slack-aware session viewer with branching (#51).
- Login: built-in credential presets and a redesigned credential portal.
- Sandbox: image-mode container CPU/memory limits (#50), bridge network isolation, `ffmpeg` in the tools image.
### Fixed
- Discord: normalize thread sessions; queue follow-up messages; persistent channel sessions; hide usage summary by default.
- Events: restore Slack synthetic notifications (#52).
- Attachments: wait for downloads before the agent accesses them.
## [0.2.0-beta.2]
### Added
- Per-user vault system for actor-scoped credential isolation (#24).
- Managed image sandbox (`--sandbox=image:<image>`) (#47).
- Login flow wired into the runtime; credential onboarding server (#32, #34).
- Slack: `/pi-new` and `/pi-login` DM commands.
- Events: actor-aware scheduling tool (#36, #39).
### Changed
- Internal contracts unified around "conversation" naming across adapter, store, config, log, and UI layers (#38, #41, #42, #43, #44, #46).
### Fixed
- Telegram: handle bare `stop` in shared chats; escape unsupported HTML entities.
- Slack: queue follow-up messages per session.
## [0.2.0-beta.1]
### Added
- File-backed credential vault (#31) and per-user vault routing (#33).
- OAuth: GitHub redirect flow, scope parity with `gh` CLI, gcloud OAuth.
- Sandbox: separate `stateDir` from `workspaceDir` to keep secrets out of sandboxes.
### Security
- Hardened vault writes, file permissions, and login flow.
- Stopped leaking secrets in `docker exec` args.
- Enforced vault sandbox isolation policy.
### Changed
- Renamed `docker` sandbox mode to `container` (breaking).
- Replaced `DockerProvisioner` with `DockerContainerManager` + idle stop.
## [0.2.0-beta.0]
### Added
- Sentry integration for error monitoring, tracing, and metrics (#21).
- Persistent session management with in-thread replies (#18).
- Telegram: native slash commands; private-chat session fix (#15).
- `pi-coding-agent` extension loading (#12).
## Earlier releases
For releases prior to `0.2.0-beta.0` (i.e. the `0.1.x` line), see the [git tag history](https://github.com/geminixiang/mikan/tags).