Skip to content

Releases: muen-collective/mitsumeru-app

Mitsumeru 0.2.8-dev

Mitsumeru 0.2.8-dev Pre-release
Pre-release

Choose a tag to compare

@muen-dev muen-dev released this 23 Oct 15:31

Mitsumeru 0.2.8-dev

Internal build — carries the -dev suffix; the update channel is dev.

Wraps DeepSeek Harness 0.2.1-rc.2, unchanged. This cut is the updater's: one loop fixed, and
the regression test that would have caught it.

What changed

  • A scheduled check can no longer move you backwards (founder, 2026-10-23: "i updated and
    restart but i did again so I think theres a bug somewhere"
    ). A build carrying an unpublished
    version sat ahead of the channel, so every check found the older published version, and because
    allowDowngrade was true for every check, electron-updater offered it, autoDownload fetched
    it, and the banner offered a restart that could only ever go back. The version string never moved
    forward, so the next check offered it again — a loop with no exit, driven by a timer.

    allowDowngrade now follows the trigger: a person asking (the pill, the menu's Check for
    Updates
    ) may roll back; a scheduled check, a resume check and the startup check may not. Rollback
    is a decision, not a side effect.

  • A downloaded version equal to the running one is never offered. electron-updater already
    filters equal versions itself, so this is the last word rather than the first defence — but it
    costs one comparison and closes the case where a cached download and the running bundle disagree.

  • The updater smoke gained case C: a stand-in feed serving a genuinely older version, asserting
    that a scheduled check neither offers it nor downloads it. Mutation-tested — restoring
    allowDowngrade = true fails the case with "a scheduled check OFFERED the older 0.2.8-alpha.1",
    which is exactly the loop that was reported.

A note on the fixture, because it bit

The first version of case C used 0.2.8-older as the "older" version. Pre-release tags sort
alphabetically in semver, so older > dev and the app correctly offered it as an update —
the test was wrong, not the fix. It now uses -alpha.1.

What to check

  • Leave the app running past its startup check. The pill should stay invisible, and the log should
    read update-current version=0.2.8-dev.
  • Nothing else moved: the folder chooser from 0.2.7-dev, the update pill, the account row and the
    collapsed rail are as that release left them.

Mitsumeru 0.2.7-dev

Mitsumeru 0.2.7-dev Pre-release
Pre-release

Choose a tag to compare

@muen-dev muen-dev released this 22 Oct 23:41

Mitsumeru 0.2.7-dev

Internal build — carries the -dev suffix; the update channel is dev.

Wraps DeepSeek Harness 0.2.1-rc.2, unchanged from 0.2.6-dev. This cut is the shell catching up:
one behaviour fix, no harness change.

What changed

  • A new workspace folder can be named (founder, 2026-10-22: "I can open finder but when I try
    to create new folder, it can't give it a name"
    ). The sidebar's new-project flow opened the
    harness's own macOS picker, which is an NSOpenPanel run by a separate osascript
    accessory process
    . That panel is never the app window's key window, so New Folder created a
    folder but its rename field refused every keystroke — the name had to be accepted as
    untitled folder and renamed afterwards in Finder.

    The shell now exposes __DSH_DIRECTORY_PICKER__ — the same global DSH's own desktop exposes —
    and answers it with an Electron sheet attached to the main window (openDirectory +
    createDirectory). Naming a folder is ordinary text entry again: type, press Return, choose.
    The harness client prefers that bridge whenever it exists, so nothing in the pinned harness
    changed and no upstream patch is carried.

    Verified on a live run before the cut: the dialog's owner is the app, no osascript process is
    involved, the sheet carries New Folder / Cancel / Choose, and a pick completed with a newly
    created folder. The founder then drove the same dialog by hand and confirmed the name can be
    typed.

What to check

  • Sidebar → new workspace → New Folder → type a name → Return → Choose. The folder should be
    created with the name you typed and selected as the workspace.
  • Nothing else moved: the updater pill, the account row and the collapsed rail are as 0.2.6-dev
    left them.

Mitsumeru 0.2.6-dev

Mitsumeru 0.2.6-dev Pre-release
Pre-release

Choose a tag to compare

@muen-dev muen-dev released this 20 Oct 08:59

Mitsumeru 0.2.6-dev

Internal build — carries the -dev suffix; the update channel is dev.

These binaries replace the ones published earlier today. The first cut of 0.2.6-dev shipped an
updater guard that could not work: it remembered the installed version in memory, and
quitAndInstall() ends the process. Installing that build and restarting would have re-offered the
same update — the exact bug the guard was written for. The assets under this tag were rebuilt and
replaced at ~11:20 UTC on 2026-10-20; GitHub reports only the publisher's own verification downloads
against the earlier ones. If you downloaded before then, download again — the version string is
unchanged, so nothing would ever offer you the fix.

Wraps DeepSeek Harness 0.2.1-rc.2 (0.2.5 carried 0.2.1-alpha.2; rc.2 shipped 2026-10-17). The
pin is the only thing that had to change to wrap it — the harness version is data, not code. An rc pin
never ships to latest, so this build stays on the dev channel deliberately.

What changed

  • DSH desktop parity — the rail now collapses all the way to zero (founder, 2026-10-12:
    "i want full parity", after "dsh left rail collapse all the way, this is the design I always
    wanted"
    ). The shell now marks the document <html data-platform=darwin>, which is the single
    attribute the harness reads to switch three behaviours at once:
    • the collapsed sidebar's width becomes darwin ? 0 : 56, so a closed rail leaves nothing on
      the left instead of a 56px icon column (ui-layout);
    • the desktop chrome turns on — [data-window-drag] regions, the translucent New-session button,
      the sidebar gradient;
    • the native keyboard bridge becomes mandatory: with the mark set, dsh-client-shortcuts
      throws Desktop keyboard bridge unavailable unless window.dshDesktop.keyboard exists, and the
      frame does not mount at all.
  • The native keyboard bridge is real, not a stub. In desktop runtime the DOM key path serves only
    fixed actions, so the configurable bindings must arrive over IPC. The main process imports the
    harness's own published domain module (@deepseek-ai/dsh-client-shortcuts/protocol) to resolve the
    binding table, claims registered chords on before-input-event, and delivers them to the page.
    Preferences persist at <stateDir>/keybindings.json.
  • Window chrome: titleBarStyle: hiddenInset with trafficLightPosition {x:16, y:18},
    vibrancy: 'sidebar' and a transparent background — the official shell's own darwin values. The
    vibrancy matters: under the mark the harness's frame is background: 0 0 and its sidebar is a
    color-mix(…, transparent) gradient, so a native material has to sit behind it.
  • Safety: the preload marks the document only when the bridge is confirmed live, so if the
    protocol module cannot load the app degrades to the previous behaviour (56px rail, working app)
    rather than a dead boot. The previous session's rail-collapse.ts injection stays as the fallback.

Fixed after the first parity build (same day, founder's eyes)

  • The colour was off. The native material behind the sidebar followed the OS appearance while the
    app ran its own theme, so a light app on a dark system translated a dark grey panel behind a light
    UI. The shell now mirrors the harness's theme source (html[data-ds-theme-source], system |
    light | dark, written by ui-layout) into Electron's nativeTheme.themeSource, which fixes the
    material, the window chrome and renderer prefers-color-scheme in one step. Fullscreen is mirrored
    the same way, so the harness's 48px title-band clearance and the hidden traffic lights agree.
  • "If I click settings, another menu pops up top left." Our Muen account overlay (Epic 92) hid the
    stock settings rail and then clicked the hidden launcher button. A hidden element measures 0x0,
    so anything anchored to it opens clamped at the window's top-left. Root cause, read from the
    harness's own source: the settings.launcher slot is filled by AccountMenu — that launcher is
    the account menu's anchor, which is why the stray panel was the account menu (Settings / Feedback /
    Sign in). The overlay now opens Settings through the harness's command path instead —
    {kind:'menu', commandId:'settings.open'} over the bridge, the same mechanism the official shell
    drives its File menu with — which involves no DOM anchor and no key gesture at all.

Fixed at the founder's review (same day, later)

  • The avatar's Language menu listed two languages, not the catalog (founder, 2026-10-12: "the
    language switcher from avatar only show zh, en, needs full set from language switcher"
    ). The menu
    carried a hardcoded en/zh pair whose comment said it was the harness's shipped catalog — true,
    and exactly why it was wrong: the other five languages arrive from @muen/dsh-localize through
    the runtime's addLanguage, and this menu was the one place the catalog never reached. It now reads
    <html data-muen-languages="[{id,label}]"> — the mirror that plugin publishes, in the runtime's own
    order — and falls back to the built-in pair when nothing published one (a stock DSH, or a profile
    without the plugin). The rows are rebuilt on open, not at inject time, because the overlay is
    injected as the app boots, before any plugin has offered its languages.

The update strip is gone (2026-10-20)

  • The banner across the top of the window became a pill beside the account row. A full-width strip
    took permanent screen space to say something true for about a minute, and it sat in the window chrome
    rather than the account area where app-level actions live. It is replaced by what DSH Desktop does: a
    small button — 14px glyph + label — injected into the avatar row, drawn only while there is something
    to say. The glyph carries the phase (download arrow when available, spinner while checking /
    downloading / verifying, check when downloaded, dot on error) and the click does what the phase
    implies: Restart when downloaded, Retry on error, Release notes when available, nothing
    while busy. The visibility rules carry over from the banner unchanged — checking and current
    only appear when a person asked, error only when they asked or when an update was already in
    flight — because that reasoning was about not interrupting someone, not about where the thing is
    drawn. update-banner.ts is deleted; update-indicator.ts replaces it.
  • A 100% download is not "done". electron-updater still verifies and unpacks after the last byte,
    and the old progress bar sat frozen at 100% through that gap. verifying is a state now, so the pill
    says what is happening instead of looking stuck.
  • A version already handed to quitAndInstall is not offered again on the next check (founder,
    2026-10-19: "when I restarted it did the update banner again"). After the relaunch the on-disk
    version may not have changed yet, so the same version came back as available. The updater now
    remembers what it asked Squirrel to install and reports current instead — and the marker lives on
    disk (<userData>/update-installed.json), because quitAndInstall() quits the process: the
    first cut of this guard was an in-memory value that could not survive the relaunch it existed for.
    It is bounded so a failed install still re-offers: 15-minute TTL, consumed on first use, and dropped
    at startup when the running version is already the marked one.
  • The account row spans the sidebar instead of floating as a pill: it reads the sidebar column's
    live box, follows a resize, reserves its own height at the foot of the rail so content scrolls above
    it, and hides when the rail collapses to zero — it lives inside the rail, so it goes with it. It is
    transparent, not a token fill: on macOS the sidebar paints a gradient plus a color-mix over
    --dsw-specific-sidebar-fill, so any flat copy of that token leaves a visible seam along the row's
    top edge. The row is a <button>, so the UA's outset border had to be reset — that border was the
    white line it wore.
  • No leading seat was built, deliberately. DSH's sidebar toggle and New Session buttons are its own
    HeaderLeadingControls, mounted by AppFrame when darwin && sidebarCollapsed. This shell already
    sets data-platform, so they were mounting all along; an injected copy only stacked a second pair on
    top of them. The native pair keeps its own icons, tooltips and React handlers.

Gates

This cut was made with pnpm release:cut, which stops at the first failure and never publishes. Every
step below ran, in order, on the artifacts that are attached to this release:

  • check:label, check:identity, typecheck — clean.
  • package:mac — both arches built and signed with Developer ID Application: THUY QUANG PHAM
    (4Q6GC57QG4)
    , each carrying a secure timestamp.
  • notarize:all — 8 submissions accepted by Apple's notary service (app bundle + final dmg, per
    arch), each stapled, and every staple and validate reported worked. Gatekeeper accepts them.
  • smoke — 5/5: harness readiness line, UI loaded, clean quit, no orphan harness, app exited.
  • smoke:native — the native surfaces against the packaged app.
  • verify:surfaces, verify:mount, verify:release — all green, including the mount probe reading the
    served bundle and the frame's own seats.
  • verify:artifacts — 20/20: each dmg/zip carries its own arch's addon and not the other's, and the
    Windows NSIS payload is x86-64 with the win32-x64 addon and every shipped @muen plugin.
  • verify:docs — "docs agree with the code".

Two gates failed first and were fixed rather than waived, because both were the gate's fault and not the
build's:

  • smoke blocked on a Keychain prompt. It shared userData with the installed app, so it read that
    app's stored Muen session an...
Read more

Mitsumeru 0.2.5

Choose a tag to compare

@muen-dev muen-dev released this 11 Oct 18:25

Mitsumeru 0.2.5

Promoted release: no -dev suffix, so this takes the latest channel. Shipped three targets:
Apple Silicon, Intel and Windows x64.

This is the build that was dogfooded as 0.2.5-dev, promoted under its own name. The -dev
drills (0.2.4-dev, 0.2.5-dev) stay published and keep their own channel, so nothing already
installed is disturbed.

Wraps DeepSeek Harness 0.2.1-alpha.2, from 0.1.7-rc.1, which is what 0.2.3 shipped.

What changed since 0.2.3

Sign-in is required. A fresh install opens at the sign-in screen. There is no anonymous use,
the harness does not start until a session exists, and signing out stops it and returns to the
gate. Sign-in opens the Muen site's sign-in route in your browser; the mitsumeru:// callback
returns into the app, where avatar and tier read the same membership record the site sees. The
entry also registers the mitsumeru:// protocol pair, so links from the site round trip back
into the app.

The Plugins page shows what you actually have. It renders the shipped Muen bundles (they were
invisible before: the profile listed them and the page filtered them out), the account row shows
your account name, and Settings now lives in the avatar menu (the old gear rail is hidden;
Cmd+, still works). Every @muen/* plugin card wears the same Experimental badge DSH gives its
own preview plugins.

Retired inside the build: dsh-turn-summary and dsh-codex-fold left the shipped set. What
remains vendored is brand, EVA theme, white-label, context-watchdog and changes-card.

Avatar row polish: the light-theme label is fixed and the avatar ring is gone.

The harness re-pin. 0.1.7-rc.1 to 0.2.1-alpha.2. The supply-chain age gate holds the harness
closure as an explicit, version-reviewed exception list, and a re-pin must retarget it or the build
refuses to run: 289 entries were retargeted here. Every re-pin is audited against the three
upstream breakage classes (settings and service surfaces, composition gates, profile bundles).

What is not in this build

The Generate, Assets and localisation plugins are not here. They are separate packages that
ship from the market: install them in Settings to Plugins by URL. This build is the shell, the
harness and the brand. Private-plugin gating and pricing are also not here; they ship with the
Muen plugins installer in the 0.2.6 line.

Gates

Run by pnpm release:cut, which stops at the first failure and never publishes:

  • PROMOTE=1 check:label (the -dev suffix must be gone from the version and from every artifact)
  • check:identity, typecheck
  • build and sign all three targets, then notarize:all and manifest:merge
  • smoke, smoke:native, verify:surfaces, verify:mount
  • verify:release, verify:artifacts, verify:docs

Install

Artifact Architecture
Mitsumeru-0.2.5-arm64.dmg / -arm64-mac.zip Apple Silicon
Mitsumeru-0.2.5.dmg / -mac.zip Intel (x86_64)
Mitsumeru Setup 0.2.5.exe Windows x64
  • Apple Silicon: Mitsumeru-0.2.5-arm64.dmg
  • Intel: Mitsumeru-0.2.5.dmg
  • Windows: the .exe installer. It is unsigned, so Windows shows SmartScreen: More info
    then Run anyway.

Both Mac builds are notarized and stapled, so they open on a double-click. latest-mac.yml and
latest.yml are the update feeds; latest-mac.yml is the one a promoted client reads, so a
0.2.3 install is offered this build automatically.

Mitsumeru 0.2.5-dev

Mitsumeru 0.2.5-dev Pre-release
Pre-release

Choose a tag to compare

@muen-dev muen-dev released this 10 Oct 04:25

Internal build — carries the -dev suffix; the update channel it belongs to is
dev.

The same app, on a new harness, with sign-in. This build re-pins DeepSeek
Harness 0.1.7-rc.1 → 0.2.1-alpha.2 (the 0.2.0-rc.2 → alpha.1 → alpha.2
re-pin chain of 2026-09-29…10-09; an alpha pin never ships to the latest
channel — 0.2.6 waits for the 0.2.x rc).

Sign-in is now required. The first-install gate (founder direction
2026-10-02): a fresh install opens at the sign-in screen — no anonymous use,
the harness does not start until a session exists, and explicit sign-out stops
it and returns to the gate. Sign-in opens the deployed Muen site's sign-in
route in your browser; the mitsumeru:// callback returns into the app, where
avatar and tier read from the same membership record the site sees. The entry
also registers the mitsumeru:// protocol pair, so links from the site round
trip back into the app.

Plugins page shows what you actually have. The page renders the shipped
Muen bundles (they were invisible before — the profile listed them but the page
filtered them out), the account row shows your account's name, and Settings now
lives in the avatar menu (the old gear rail is hidden; ⌘, still works). Every
@muen/* plugin card wears the same Experimental badge DSH gives its own
preview plugins — one patched predicate in the plugin-manager client, inside
the app signature, with a build gate so a future harness bump that changes the
line fails the cut instead of shipping unbadged.

Retired inside the build: dsh-turn-summary and dsh-codex-fold left the
shipped set (founder, 2026-10-02). What remains vendored: brand, EVA theme,
white-label, context-watchdog, changes-card.

Avatar row polish: light-theme label fixed, no avatar ring.

The bump's own findings. The supply-chain age gate holds the harness
closure as an explicit, version-reviewed exception list (289 entries retargeted
to 0.2.1-alpha.2); a re-pin must retarget that list or the build refuses to
run. Every bump is audited against the three upstream breakage classes
(settings/service surface, composition gates, profile bundles).

Unchanged: private-plugin gating and pricing are not here — the Muen
plugins installer ships later (0.2.6 line). Windows ships unsigned, so first
run needs one More info → Run anyway click.

Wraps DeepSeek Harness 0.2.1-alpha.2 (from 0.1.7-rc.1).

Packaged for all three targets — Mitsumeru-0.2.5-dev-arm64.dmg +
-arm64-mac.zip (Apple Silicon), Mitsumeru-0.2.5-dev.dmg + -mac.zip
(Intel) and Mitsumeru Setup 0.2.5-dev.exe (Windows x64). Both Mac builds are
notarized and stapled; the feed is the merged dev-mac.yml, with dev.yml
for Windows.

Install: Mitsumeru-0.2.5-dev-arm64.dmg (Apple Silicon),
Mitsumeru-0.2.5-dev.dmg (Intel), or Mitsumeru Setup 0.2.5-dev.exe
(Windows x64), from this release's assets. A 0.2.4-dev machine is offered this
build by the app itself through the update banner.

Mitsumeru 0.2.4-dev

Mitsumeru 0.2.4-dev Pre-release
Pre-release

Choose a tag to compare

@muen-dev muen-dev released this 29 Sep 20:17

Internal build — carries the -dev suffix; the update channel it belongs to is
dev.

The app now announces its own updates. Until now a release reached you
because a person said so — the shell checked, downloaded and waited, but said
nothing, and an update could sit unseen until someone mentioned it. A 36 px
shell-owned strip at the top of the window surfaces that state: a check you
trigger flashes "up to date" for three seconds, an available update offers
Download, progress runs against a named version, and a finished download offers
Restart to update. A failure shows when you asked for a check, or when an update
already in flight died, and stays quiet otherwise (10 s); dismiss hides the
strip until the state next changes. It has to be shell-owned — quitAndInstall()
is an Electron API, and a harness plugin cannot drive any of this.

Running the five states against the packaged app with a local stand-in feed
caught two bugs, both fixed here: an error after a failed restart hid itself
(the strip still believed the state was downloaded), and the progress line
read "Downloading v… 22%" because download-progress events carry no version of
their own.

Muen sign-in, in the slot DeepSeek Desktop uses. The lower-left avatar is
that same seat: signed out it shows the Muen mark, and a click starts sign-in —
GitHub OAuth in the browser, a mitsumeru://auth/callback?code=… deep link back
into the app, and a code exchange the shell performs in the main process. The
session lands encrypted (safeStorage) at <userData>/auth/session.enc; the
token never leaves the main process, and the injected overlay only ever sees the
profile. Signed in, the avatar shows your picture (your initial if the image
fails to load), with a PRO badge when the session says membership: pro.
The deep link needed a protocols entry in the build config — without it macOS
hands the URL to nobody and sign-in can never complete.

The avatar opens a menu, and the language switcher moved into it. The row
opens on click, the DeepSeek Desktop pattern: Language (English / 中文),
separator, Sign out. The language item writes the harness's own locale
preference over the same wire Settings → General uses, so the two surfaces
cannot disagree — and the client applies it live, html lang flipping in about
2.5 s with no reload. The overlay takes the new language on the click itself, so
its own bilingual labels do not trail the app; the menu closes on an outside
click and on Esc, and a failed switch shows an inline error instead of ignoring
the click.

What is deliberately not in this build. Sign-in was verified against a local
mock auth server; the production service is not standing yet, and the build
points at mitsumeru.vercel.app (MITSUMERU_AUTH_ORIGIN moves it for a run).
Private-plugin gating — the part that reads membership and unlocks the Muen set
— is not here either.

Wraps DeepSeek Harness 0.1.7-rc.1 — unchanged. The re-pin to 0.2.0-rc.2 follows
as its own release, so a shell change and a harness change can be told apart if
something misbehaves.

Packaged for both Mac targets — Mitsumeru-0.2.4-dev-arm64.dmg +
-arm64-mac.zip (Apple Silicon) and Mitsumeru-0.2.4-dev.dmg + -mac.zip
(Intel) — signed with a Developer ID, notarized and stapled (every artifact
carries its ticket), with the merged dev-mac.yml feed. The Windows installer
follows with the production cut. Gates: check:label / check:identity /
typecheck; pnpm smoke (5/5);
pnpm smoke:updater (14/14, against the packaged build); the five banner
states, sign-in and sign-out, session restore across a SIGKILL and relaunch,
and the language switch — all against the packaged app, all screenshot-asserted
(artifacts/current-*, error-*, downloaded-*, auth-*, menu-*).

Install: Mitsumeru-0.2.4-dev-arm64.dmg (Apple Silicon) or
Mitsumeru-0.2.4-dev.dmg (Intel), from this release's assets. A machine on the
dev channel is offered it by the app itself. From this build on the app
announces its own updates — this is the last release that had to be relayed by
hand.

Mitsumeru 0.2.3

Choose a tag to compare

@muen-dev muen-dev released this 26 Sep 15:02

Production build — latest channel, like 0.2.0, 0.2.1 and 0.2.2. This release ships three
targets: Apple Silicon, Intel, and Windows x64.

The Generate, Assets and localisation plugins are NOT in this build. They are separate packages that ship
from the market, by the founder's decision of 2026-09-26 — install them in Settings → Plugins by URL
(@muen/dsh-generate 0.2.2, @muen/dsh-assets 0.2.1, and optionally @muen/dsh-localize 0.1.0). This build is
the shell, the harness re-pin and the brand.

The brand now travels inside the build. Until now a white-label brand lived
only in runtime state, so installing a new core looked exactly like losing it:
the tagline, the status label, the accent and the marks were gone, and re-adding
them by hand did not survive the next launch either. The cause was an upstream
API change, not the plugin's logic.

DSH 0.1.6-alpha.2 exposed settings.register(namespace, schema, { base }), and
@muen/dsh-white-label used it. 0.1.7-rc.1 removed it — the settings service
now exposes configure, describe, update, replace and mutate, and
nothing else. The call threw register is not a function into the catch that
had been there to tolerate a namespace someone else had already taken, so it
failed silently: nothing logged, the namespace never resolved, and persistence
fell back to the browser's localStorage mirror. That mirror is not durable —
the harness serves a fresh port on every launch and localStorage is
origin-scoped — so the brand was wiped by the next start.

0.1.7 also replaced that API with a better one, and the plugin now uses it: a
plugin's durable namespace is its own profile entry id
, and its Config is the
namespace, projected to the browser when it carries volatile() fields. So the
brand is not copied into a state directory and it is not baked into a client
bundle. It is config in the layer that belongs to the build — the plugin's
own bundle patch — and the patch layer order does the rest:

Layer Holds Outranks
the plugin's bundle patch the brand this build ships —
the profile's cordis.patch.yml what a person saved in Settings → Brand the build's brand
$DSH_HOME/cordis.patch.yml an operator's machine-wide override both

The consequence is the one that matters for release: a brand someone saves
survives an app update
, and Reset restores the shipped values.

Ship or change the brand from one file. build/brand/white-label/brand.json
plus the PNGs beside it are the whole input, and scripts/apply-white-label-brand.mjs
folds them into the vendored plugin's patch during the build (prepare-harness.sh
runs it after vendoring, so it always writes onto a fresh copy). Delete that
folder and the build ships the plugin's neutral defaults — no build carries an
identity it was not given. This build ships the authored brand: the tagline, the
run-status label, the light accent, and the light/dark wordmark pair.

The accent is durable too. It had the same failure mode, and it rides the
same document now — keeping it in localStorage alone would have reproduced the
loss for anyone who picked a colour.

A duplicate Brand page is suppressed. A schema with volatile() fields
auto-generates a Settings page, and auto defaults to true, so declaring the
Config would have put the brand on a second, generated page as well as the
plugin's own. The plugin registers configure({ auto: false }, ctx.fiber) as an
effect, per the dsh-settings README rule for a plugin that ships its own page.

A new harness underneath: DeepSeek Harness 0.1.7-rc.1, up from
0.1.6-alpha.2.

The Sidebar Browser tab is off by default, and that is upstream's choice.
0.1.6-alpha.2 composed ui-sidebar-browser unconditionally. 0.1.7-rc.1 keeps the
package — @deepseek-ai/dsh-client-ui-sidebar-browser, "Sandboxed Web browser
tabs for the right Sidebar" — but gates the row on the profile being named
desktop:

# Web profiles opt in; Desktop retains sandboxed HTTP(S) Browser tabs.
- id: ui-sidebar-browser
  name: '@deepseek-ai/dsh-client-ui-sidebar-browser'
  disabled: !!js "ctx.get('profileContext')?.name !== 'desktop'"

This app's profile is named mitsu, so the gate never passes and the tab
vanishes — it is not removed, and nothing in this repo disabled it. To opt back
in, override the row by id in the profile's cordis.patch.yml:

- id: ui-sidebar-browser
  disabled: false

That is verified in a throwaway profile: the row composes with disabled: false
and the plugin reaches the DOM. One thing to know before enabling it: dsh-base
gates desktopPlatform (the DeepSeek account's desktop handoff) on the SAME
profile name, but wraps it in a fallback, so a browser-only override is safe —
while renaming the profile to desktop would also switch the account plugin
into its desktop mode
, which is a different decision than re-enabling a tab.
The override-by-id route changes exactly one thing.

Verified on this build

  • node --test tests/*.test.mjs in muen-plugins — 47 pass, including three new
    cases pinning this contract: the namespace is the entry id and not the old
    name, the 0.1.6 register call is capability-guarded rather than left to
    throw, and the accent writes through to the durable document.
  • --dump-config on a throwaway profile with an empty profile patch: the
    brand arrives from the bundle layer (brandTagline, statusLabel, accentLight,
    and both logos), and a row added to the profile layer replaces it.
  • The packaged app, in a fresh profile with empty localStorage and an empty
    profile patch: Settings → Brand reads back the shipped tagline and status label,
    and all seven brand marks render.
  • The shipped accent is live, read off the running app rather than the schema:
    --dsw-alias-brand-primary: #4f83f2 and its derived
    --dsw-alias-button-primary-hover: #6f99f4.
  • scripts/white-label-probe.cjs against the packaged harness: PASS.
  • Both architectures are notarized and stapled, and the full release gate passes
    for each: Mitsumeru-0.2.3.dmg + -mac.zip (Intel) and
    Mitsumeru-0.2.3-arm64.dmg + -arm64-mac.zip (Apple Silicon). Gatekeeper
    accepts the dmg, the zip, and the app inside each; every Mach-O binary in the
    harness tree is signed; verify:arch boots both and confirms neither carries
    the other's native addon.

Merging the feed for the first time caught a second bug, in manifest:merge: it
concatenated whatever fragments were in release/, so this build's
dev-mac.yml claimed version: 0.2.3-dev while listing the 0.2.2 Intel zip
and dmg — which an Intel client would have downloaded and installed as
"0.2.3-dev". Fragments from another version are now dropped, loudly, and a feed
with no entry for the current version fails instead of shipping. The same merge
is what makes a one-arch release visible: it warns when fewer than two artifacts
are present rather than quietly publishing a feed that strands a platform.

Fixing the accent check turned up a flaw in the probe itself: it read the token
from documentElement, while the plugin's theme override lands on <body>, so it
reported "default" for a build whose accent was applied. It reads <body> now —
the accent is the one part of the brand a screenshot cannot confirm, and a false
negative on it is exactly the kind of result that sends you re-checking a correct
change.

Known, and deliberate

A hand-written row in the profile's cordis.patch.yml replaces the whole
config object instead of merging field by field, so a row that sets only
brandTagline drops the shipped marks. The Settings UI is unaffected — it writes
the full resolved config, and Reset deletes the row and brings the build's values
back.

Install

Artifact Architecture
Mitsumeru-0.2.3-arm64.dmg / -arm64-mac.zip Apple Silicon
Mitsumeru-0.2.3.dmg / -mac.zip Intel (x86_64)
Mitsumeru Setup 0.2.3.exe Windows x64
  • Apple Silicon: Mitsumeru-0.2.3-arm64.dmg
  • Intel: Mitsumeru-0.2.3.dmg
  • Windows: the .exe installer (unsigned — Windows shows SmartScreen, so More info → Run anyway)

macOS builds are notarized and stapled, so they open on a double-click. latest-mac.yml and latest.yml are the
update manifests and ship beside the binaries.

Windows needs Node and pnpm once before the app can install a plugin: install Node LTS, then
npm install -g pnpm. Mitsumeru ships no package manager, and DSH forwards every plugin install to pnpm in the
profile directory. The full runbook for a Windows machine is
docs/status/2026-09-26-aria-windows-install.md in the product workspace.

Mitsumeru 0.2.2

Choose a tag to compare

@muen-dev muen-dev released this 20 Sep 14:12

Production build — latest channel, like 0.2.0 and 0.2.1. This release ships three
targets: Apple Silicon, Intel, and Windows x64.

Intel and Windows are back, and this time they work

0.1.9-dev's Intel dmg and Windows exe have never started. 0.2.0 and 0.2.1 shipped
arm64 only, by decision, because the alternative was handing out builds that could
not launch. Both facts had the same cause, and it is fixed here.

prepare-harness.sh staged the host closure with no platform handling at all, and
electron-builder copies that ONE tree into every target it builds. So the x64 app
and the Windows exe both received Apple Silicon native addons —
node-addon-require-builtin-darwin-arm64 — and an x86_64 process cannot load arm64
code. Rosetta does not go that direction. The build log had been listing every
platform-specific dependency it could not bundle, in every build:

platform-specific optional dependencies not bundled … node-addon-require-builtin-darwin-x64, … win32-x64-msvc, @koromix/koffi-darwin-x64, @vscode/ripgrep-darwin-x64, @img/sharp-darwin-x64 …

Staging is now per target (--os / --cpu, writing supportedArchitectures into
the stage), and the build is per target too, so what gets packaged is what was
staged:

Artifact Architecture
Mitsumeru-0.2.2-arm64.dmg / -arm64-mac.zip Apple Silicon
Mitsumeru-0.2.2.dmg / -mac.zip Intel (x86_64)
Mitsumeru Setup 0.2.2.exe Windows x64

Two further traps had to go, both of which silently produced the wrong build: the
notarize step deleted every artifact and repacked from release/mac-arm64 (that
is how a two-arch release became arm64-only in 0.2.0 and 0.2.1), and the repackage
invocation had no arch flag, so electron-builder packaged for the host and
handed back arm64 artifacts for an Intel app. Both are fixed and both are now
asserted rather than trusted.

Windows is unsigned in this release

Mitsumeru Setup 0.2.2.exe carries no Authenticode signature — there is no
Windows code-signing certificate on this rig, and the certificate is a purchase
with identity validation (Azure Artifact Signing is the cheapest path at ~$10/mo;
OV certificates start around $150/yr). Expect "Windows protected your PC" on
first run: More info → Run anyway. That is the unsigned path behaving as
documented, not a packaging fault.

Worth knowing before buying: EV certificates stopped bypassing SmartScreen in
2024
, so paying the EV premium for that reason is no longer justified. Any valid
certificate still helps — reputation accumulates against a consistent publisher
identity and carries across releases, while unsigned builds start from zero every
version.

Gates

  • pnpm verify:release — 36 checks, 0 failures, run once per architecture: both
    apps signed with the Developer ID and carrying a secure timestamp, both dmgs
    accepted by Gatekeeper and stapled, the app inside each zip and inside
    each dmg carrying a stapled ticket and passing Gatekeeper, and all four
    latest-mac.yml entries matching sha512 and size on disk. The gate also fails a
    feed that lists fewer than four artifacts — the shape an Intel client experiences
    as "no update available".
  • pnpm verify:arch — each app's Mach-O architecture, the harness addon it
    must load, and the absence of the other architecture's addon; then a real boot
    of the packaged harness on the package's own Electron. The Intel app is booted
    under Rosetta, and it serves its page.
  • PROMOTE=1 pnpm check:label — 8/8, including all four artifacts carrying the
    version and the packaged app reporting it.

Known, not fixed in this release

  • Windows is unsigned (above).
  • verify:survives-update still fails on @muen/dsh-white-label importing
    @deepseek-ai/schemastery without declaring it, so installing that plugin from
    source cannot resolve it. Carried from 0.2.0; the shipped app is unaffected.
  • @muen/dsh-codex-fold's Settings card ("Status text") cannot render on DSH
    0.1.6-alpha.2: settings.plugin.item is declared by no bundle. Its folding is
    unaffected.
  • The download page's Windows row stays off until the installer is signed. The page
    itself is already architecture-aware and deployed (2026-09-18): it picks the Intel dmg
    when the browser reports x86, recommends the matching row, and lists the other
    architecture beside it. One step happens with this publication — the static fallback
    href moves from 0.2.1 to 0.2.2, because verify:distribution downloads the fallback
    rather than the release the page resolves at load.

Install

  • Apple Silicon: Mitsumeru-0.2.2-arm64.dmg
  • Intel: Mitsumeru-0.2.2.dmg
  • Windows: Mitsumeru-Setup-0.2.2.exe (unsigned — see above)

macOS builds are notarized and stapled, so they open on a double-click.
latest-mac.yml and latest.yml are the update manifests and ship beside the binaries.

The .exe asset name is hyphenated on purpose: electron-builder writes that name into
latest.yml's url, and the Windows updater downloads what the manifest names. The local
build output keeps the space (Mitsumeru Setup 0.2.2.exe); only the uploaded asset is
renamed.

Mitsumeru 0.2.1

Choose a tag to compare

@muen-dev muen-dev released this 19 Sep 01:12

Production build — the -dev suffix stays off and this leaves the latest
channel, like 0.2.0. Version 0.2.1 adds the quality-of-life plugin set.

This release is arm64-only, deliberately, for the same measured reason as 0.2.0.
prepare-harness.sh stages one host closure for every target, so the x64 and Windows
builds receive Apple Silicon native addons and an Intel process cannot load them. The
manifest lists only arm64 artifacts, so an Intel client finds no suitable file and stays
where it is rather than being handed a build that will not start. Intel and Windows
remain on 0.1.9-dev until the staging learns platform handling.

What's new: the daily-driver set

Four plugins built to make Mitsumeru livable as the every-day app — the surfaces that
were being missed after moving off Kun — now ship inside the build:

  • Turn summary — one muted, localized row per finished turn: Processed 1m 26s ·
    12 steps · Edited 3 files
    . It expands into what the turn actually did.
  • Changes card — a changed-files card at the end of a turn: Edited 3 files +6 −1
    with per-file rows, computed from the turn's own file tools, so it also appears where
    the Host's change recorder announced nothing.
  • Codex fold — finished turns fold, and the thinking/tool/context runs between prose
    collapse into one summary chip per run; expanding shows the native rows again.
  • Context reminder — a full-width banner above the composer once a session passes a
    model-aware threshold (max(floor, min(percent% × window, ceiling)), default 35% capped
    at 300K and floored at 25K), offering a fresh session, a token-banded snooze, or
    dismissal — plus Settings → General → Context reminder, the row that owns the policy.

The first three are Client-only surfaces over the conversation; the fourth adds one
preference row and reads the same contextPressure projection the harness's own context
meter reads. Each has an empty Host half, so nothing about them can drift from the
harness's own state.

The set is composed into the app, not offered by it

SHIPPED_PLUGINS in the shell is one literal list, and ensureProfile recomputes the
profile's bundle list from it on every launch. So an app that is already installed
gains these four on the next start, without deleting the profile and without touching
sessions, settings or the brand. They are vendored into the harness resource by
prepare-harness.sh — that is, they sit inside the code signature, rather than being
added to an installed app afterwards.

What deliberately does not ship

dsh-auto-collapse (community). Codex fold is its localized fork, and the two fold
the same runs: shipping both double-folds a single conversation. The dev profile had the
community package installed (already uncomposed) and it has been removed. Everything else
community stays where it belongs — in the market, installed per profile:

  • browser-skill needs its Chrome extension, so it cannot work as a baked-in surface.
  • codex-connect is a third-party OAuth provider that updates itself from the registry;
    vendoring it would freeze an alpha inside a signed artifact and make its updates ours.

The rule this makes explicit: the app ships Muen's own plugins; the market serves the
community's.

One visual defect fixed on the way in

A folded-work summary chip was rendering one size larger than every native row around
it
— 14px where the harness's rows are 13px — and it did so invisibly: the chip's
stylesheet declared the right tier, but the chip sets font: inherit inline on a button
inside the conversation body, and the inline declaration wins.

The chip now follows the harness's published row contract (DisclosureRow.module.css:
title on the secondary tier, row height / leading box / glyph edge shifted by
--dsh-content-font-delta), so it also tracks the Settings font-size preference the way
native rows do. The distinction between our rows and the harness's moves to colour, where
it belongs: our labels stay one step dimmer, and the chip's detail — previously brighter
than its own label — takes the caption tier.

Where the source lives

The four are published from
muen-collective/muen-plugins
(plugins/dsh-turn-summary, dsh-changes-card, dsh-codex-fold,
dsh-context-watchdog), and vendored into this app as byte-identical mirrors. They were
developed as workspace links with no version history; this release is their promotion.

The sidebar brand seat no longer picks its owner by accident

@muen/dsh-brand-mitsumeru and @muen/dsh-white-label both registered the same
three exclusive seats — sidebar.brand.mark, sidebar.brand.name and
conversation.hero.brand.mark — at the same priority. A single slot does not merge
those, it refuses the second registration with an uncaught error, so one of the two
threw on every launch (visible only in a console nobody reads), and which mark you saw
came down to registration order. It had been that way since 0.2.0.

The owner of those seats is now a decision rather than a race: the configuration layer
owns them when a brand is actually configured
— an uploaded mark, or the filesystem
brand folder — and the product mark keeps them otherwise. White-label claims them at a
lower priority, which is how this slot system expresses a deliberate shadow, and only
when there is a brand to show: every one of those renderers returns nothing without a
brand source, so claiming the seats unconditionally would have replaced the Mitsumeru
mark with empty space. The hero tagline seat moved out of that chain entirely — it is
uncontested, and it must not depend on the three contested registrations succeeding.

Measured by the mount gate in a fresh profile: one console error before, none after.

Gates

  • pnpm verify:release — 16/16. codesign --verify --deep --strict; the Developer ID
    signature and its secure timestamp; every Mach-O binary inside the harness signed;
    Gatekeeper on the app and on the dmg; stapler validate on both; the app inside the
    zip and inside the dmg carrying a stapled ticket; and every latest-mac.yml entry
    matching the bytes on disk.
  • PROMOTE=1 pnpm check:label — 6/6 in promotion mode: 0.2.1 carries no -dev
    suffix, both artifacts carry the version, the packaged app reports it, and no -dev
    version is named in these notes.
  • pnpm verify:mount — widened this release from one representative package to the
    composition the app actually writes: the same seven bundles, a throwaway profile, and
    assertions read back from a real renderer. Seven bundles composed and served; Settings →
    General shows the EVA theme row, both skins and the Context reminder row; zero
    console errors from any shipped bundle.
  • pnpm verify:surfaces — the sidebar brand seat carries our mark, with no upstream
    occupant left in it.
  • pnpm verify:distribution — 12/12 against the published release and the live
    download page
    : the site targets the canonical mitsumeru-app repo, its hero fallback and
    the live release name the same artifact, and the dmg a client actually downloads returns
    200, matches latest-mac.yml's sha512, passes Gatekeeper as a notarized Developer ID
    build, carries a stapled ticket, and reports 0.2.1.

Known, not fixed in this release

  • verify:survives-update fails: @muen/dsh-white-label imports
    @deepseek-ai/schemastery without declaring it, so installing that plugin from
    source
    cannot resolve it. The shipped app is unaffected — the vendored copy resolves
    it beside the harness tree. Carried from 0.2.0; the fix is declaring the dependency.
  • @muen/dsh-codex-fold's Settings card ("Status text") cannot render on this harness:
    it registers into settings.plugin.item, which no client bundle declares in DSH
    0.1.6-alpha.2 (the name exists only in a type comment), so the inject waits forever. Its
    folding is unaffected. The mount gate asserts this fact rather than skipping the row.
  • The marketing site's Vercel project no longer deploys on push: the live page was still
    the Sep 17 build, so the site's own Sep 18 commit had never gone live either. Both
    are published now, deployed with the CLI, but the Git integration itself still needs
    reconnecting — the next site commit will not appear on its own.
  • A plugin installed from a link: directory keeps its dependency spec when its contents
    change, so plugin_manager install_bundle reports ambiguous-install for a linked
    plugin whose bytes changed. The link already serves the new files; only a page reload is
    needed. Packed/tarball installs are unaffected.

Install

Download Mitsumeru-0.2.1-arm64.dmg, open it, drag Mitsumeru to Applications. It is
notarized and stapled, so it opens on a double-click.

latest-mac.yml is the update manifest and must be uploaded beside the binaries.

Mitsumeru 0.2.0

Choose a tag to compare

@muen-dev muen-dev released this 18 Sep 15:20

Mitsumeru 0.2.0 — Apple Silicon (arm64).

Wraps DeepSeek Harness 0.1.6-alpha.2 and Electron 44.0.0. Signed with Developer ID
(THUY QUANG PHAM, 4Q6GC57QG4, secure timestamp), notarized by Apple, and the app
carries a stapled ticket both inside the dmg and inside the zip.

The two fixes that were missing from every published build

Copy buttons work. Every Copy control — code blocks, tool results, diffs, terminal
output — was a click that did nothing. The cause was ours, in the shell: the app
installed a lockdown permission handler that denied every permission request, and
Chromium asks for clipboard-sanitized-write before the async Clipboard API will
write. The harness's copy helper catches that rejection and returns false, and its
caller returns early — so the button neither wrote nor showed its "Copied" state, and
there was no error to see. The fix keeps the posture and names one exception;
clipboard-read is deliberately still denied.

The hero tagline is part of the brand now, and it ships. The blank-session headline
above the composer is brand copy, so @muen/dsh-white-label owns it: Settings → Brand
→ Hero tagline
, up to 200 characters, persisted as brandTagline. Empty keeps the
shipped headline.

The headline has no slot and a plugin cannot declare one, so the seat is a narrow
additive patch to the vendored client bundle: the renderSlot("conversation.hero.tagline")
call in HeroShell and the seat's declaration in the conversation.content
factory's children table. The call without the declaration blanked every new session
on 2026-09-17. The build patches the staged harness before signing, so the seam is
inside the code signature — the previous route, patching an installed app, cost the
signature and left a .muen-unpatched sidecar behind.

Why you could not see them in 0.1.9-dev

v0.1.9-dev was built at 13:05 from c0f175a. The copy-button fix (d0a6d0e) and the
hero-tagline seam (ab21bd7) were committed at 21:44 the same day — eight hours
after the artifacts were built. Neither is in any published artifact, and this version
bump is the first build to contain them.

This release is arm64-only, deliberately

The Intel (x64) and Windows targets are not shipped. prepare-harness.sh stages the
host closure and has no platform handling, so every target carries Apple Silicon native
addons: the x64 app's node-addon-require-builtin-darwin-arm64/prebuilt/darwin-arm64-napi-v9.node
is a Mach-O arm64 bundle, and the loader resolves its prebuilt from
${process.platform}-${process.arch} — on Intel it asks for darwin-x64 and finds
nothing. An x86_64 process cannot load arm64 code, and Rosetta does not go that
direction. Shipping it would hand out a build that does not start.

latest-mac.yml therefore lists only the arm64 artifacts, so an Intel client finds no
suitable file and stays where it is rather than being handed a broken build. Intel and
Windows remain on 0.1.9-dev until the staging is fixed. (This is not new: 0.1.9-dev's
Intel dmg and Windows exe carry the same defect, so neither has ever worked.)

Gates

pnpm verify:release — 16/16, including the signature, the secure timestamp, Gatekeeper
on the app and on the dmg, stapler validate on the app and the dmg, the app inside
the zip and inside the dmg carrying a stapled ticket, and every latest-mac.yml
entry matching the bytes on disk. PROMOTE=1 pnpm check:label — 6/6. pnpm verify:mount
and pnpm verify:surfaces pass.

Known, not fixed in this release

  • verify:survives-update fails: @muen/dsh-white-label imports @deepseek-ai/schemastery
    (introduced in e9b2000) without declaring it, so installing the plugin from source
    cannot resolve it. The shipped app is unaffected — the vendored copy resolves it beside
    the harness tree. The fix is declaring the dependency.
  • verify:survives-update is not listed in package.json, so the documented
    pnpm verify:survives-update fails with "Command not found". Run it as
    bash scripts/verify-survives-update.sh.
  • The marketing site's hero fallback href still points at v0.1.9-dev. Live resolution
    (GitHub latest) picks 0.2.0 up; the static fallback needs the site repo.

Install

Download Mitsumeru-0.2.0-arm64.dmg, open it, drag Mitsumeru to Applications. It is
notarized and stapled, so it opens on a double-click — no right-click needed.

latest-mac.yml is the update manifest and must be uploaded beside the binaries.