Skip to content

v0.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 31 Aug 07:55
· 53 commits to master since this release

Added

  • swemux agent - the mux fleet tools over a second transport. Inside any swe-mux
    pane, swemux agent tools lists exactly the tools that session may call and
    swemux agent call <tool> key=value ... calls one (key:=value for JSON-typed values,
    --input for a whole JSON object). It authenticates as the calling session with the
    credentials every pane already carries and speaks to the same endpoint the MCP client
    uses, so it inherits every authority check, budget, and provenance record - and it is a
    pure passthrough, so new tools appear in it with no CLI change. A new per-harness
    "Agent CLI" toggle sits beside the MCP one under Settings → Harnesses → Fleet access;
    with both capabilities off, that harness's sessions hold no fleet surface at all and the
    daemon refuses their tokens. Every agent pane now carries MUX_SURFACES naming what it
    holds, and the shipped skill teaches whichever surface is present. In exchange, the
    session-acting operator commands (swemux send, kill, spawn) now refuse requests
    from an agent session's pane and name the agent surface instead.

  • await_session - wait for another session inside one tool call. The synchronous
    sibling of watch_session: it blocks until the target leaves working and holds a settled
    state, ends, or a bounded timeout elapses - and the timeout is a normal result carrying
    the current state, so a caller re-calls to keep waiting without ever outliving its own
    tool-call timeout. Nothing is staged or delivered; the answer is the call's return value.

  • request_spawn can now watch, place, and model its spawn in one call. watch:true
    arms the settle watch you would otherwise arm separately (deferred through human approval
    on the draft path), pane:"split_horizontal"|"split_vertical" asks the first browser
    viewing the Project to open the new session in a split beside it, and an omitted model
    now genuinely takes the target Project's new default_agent_models table (Projects →
    Repository options, or .swe-mux/config.toml) before falling back to the CLI's own
    sticky default.

  • Monitoring agents now hear their answers without a human pumping the queue. An open
    settle watch holds the watcher's auto-delivery grant open for the watch's own lifetime
    (previously any watch longer than the idle window lapsed the grant, and the notice
    arrived with nothing to deliver it), and any authenticated mux tool call now counts as
    the "somebody is reading this" evidence that resets the consecutive-send cap - so an
    orchestrator that reacts to notices by acting, rather than by writing replies, no longer
    goes silently deaf after three deliveries.

  • First-run setup asks the questions that used to wait for Settings. The tier page now
    carries a live-previewed theme picker and a Customize fold-out with two new axes: an
    agent autonomy level (Supervised / Assisted / Autonomous - whether queued messages
    deliver themselves, and under how wide a set of caps) and one checkbox per switch the
    chosen tier sets, applied atomically with the tier through the same daemon-owned policy
    route (POST /api/experience-tier now takes autonomy and overrides;
    GET /api/experience-tiers serves the tables the panel draws). The agents page gains an
    install-wide fleet access choice - MCP + CLI, MCP only, CLI + skill, or none -
    answered once instead of per harness. And setup now ends on a first steps page: the
    same three-quest card the empty workspace shows, so finishing setup hands off into the
    guided voice, worktree, and phone setups rather than closing on a blank stage.

  • The command rail can be switched off per device class. Settings → Appearance →
    Action rail: rail_enabled_desktop / rail_enabled_mobile, both on by default,
    hot-applied, and offered during first-run Customize. Turning one off hides the whole
    rail there (on mobile that includes the pinned Send button) while the configured layout
    is kept and comes back untouched.

  • The first launch of the Windows desktop shell offers to add itself to the Start Menu and
    to start when you sign in.
    A wheel cannot create a shortcut and nothing runs after
    pip/uv, so swemux install-shortcut was a command nobody knew to run. Asked once per
    install whichever way you answer, never for the installer's own build, and never when a
    Start Menu entry already exists. It writes no desktop icon; that stays a choice in
    Settings.

  • swemux start runs the daemon in the background and returns once it is serving. For
    the browser-only case, for Linux and macOS where there is no desktop app, and for
    iterating from a checkout: closing the terminal does not stop it, swemuxd --shutdown
    does, and a daemon that is already serving is reported and left alone. It is the only
    command that starts a daemon, and only when typed - swemux ls against a stopped daemon
    still says so.

  • A daemon started where you can see it opens the UI in your browser. Gated on a
    terminal actually watching the process, which is what keeps it out of every start that
    should not do this: the tray's own daemon child, swemux start's detached child, a
    restart successor, and a login task are all non-TTY and unaffected. --no-browser on
    either command, or SWE_MUX_NO_BROWSER for a caller that cannot pass a flag.

Changed

  • The side panel leads with Notes and Files, and the default rails differ per device.
    On a fresh install (or a device that never rearranged its tabs) the utility drawer's
    default order is now Notes, Files, then the session block - the two surfaces that are
    useful before a single session exists come first. The deterministic tier's default also
    puts the Activity tab away, since everything that feeds it is model-backed and off in
    that tier; choosing Automations brings it back. The Action rail's shipped layout is now
    a desktop row of mouse-verbs (copy surfaces, paste, approve, Markdown helpers, the
    pickers) and two mobile rows that keep the terminal keys, modifiers, and pads - lifted
    from a long-lived daily-driver configuration instead of one identical row on both.
    Existing arrangements and rail layouts are untouched; defaults only ever apply where
    nothing was stored.

  • notify now requires the delivery argument ("when_idle" or "now", and "now"
    requires a reason). With a silent default, senders never weighed whether the target
    should hear them before or after finishing its current turn; now the choice is made at
    every call. The message size cap also rose from 4,000 to 8,000 characters - a real task
    brief with acceptance criteria did not fit, and what got trimmed was the constraints.

  • On Windows, swe-mux now works on a plain uv tool install swe-mux or
    pip install swe-mux, with no terminal, no extra and no download.
    pystray and
    pywebview moved out of the desktop extra and into ordinary dependencies, marked
    Windows-only. Previously every install got the swe-mux launcher - it is a GUI entry
    point, so it opens no console - while an install without the extra got a launcher whose
    only behaviour was to fail on a missing import, into a message box, with both suggested
    remedies leading back through a terminal. Over 2.4 MB of pure-Python packages. The
    swe-mux[desktop] spelling still resolves and now adds nothing, so existing scripts keep
    working.

  • The mux and muxd aliases are gone. The commands are swemux, swemuxd and
    swe-mux
    - one per program, which is the floor. mux is shared with at least one
    unrelated tool in the same category, and on a machine with both, PATH order silently
    decides which one a typed mux runs. Shipping a launcher under that name is what creates
    the collision rather than what survives it; not occupying it leaves nothing to shadow.
    If a swemux ever is unreachable, swemux doctor and the daemon's own startup hint say
    so by name rather than leaving you to guess.

  • The Windows installer now ticks "Start swe-mux when I sign in" by default. A
    multiplexer that has to be launched before it can watch anything is answering the wrong
    question at sign-in. It starts hidden in the tray and the tray menu turns it off in one
    click. The desktop-icon box stays unticked.

  • swemux install-shortcut's run-at-login entry can finally be created from the UI.
    Settings → General → Desktop integration lets you choose which of the three shortcuts to
    write - Start Menu, Desktop, Start with Windows - where before it always reported all
    three, could remove all three, and could only ever create two. The only way to turn on
    run-at-login was the tray menu, which a phone or any remote client cannot reach.

  • "Start with Windows" in the tray menu now reads both mechanisms it can be turned on
    with.
    A run-at-login entry created by swemux install-shortcut --startup or by Settings
    is a shell:startup shortcut, and the menu item only consulted the registry - so it
    showed "off" beside a swe-mux that demonstrably did start at sign-in, and turning it "on"
    left two entries racing to launch the same app. Either one now counts as on, and turning
    it off clears both.

  • swemuxd now prints where the UI is and how to stop it, instead of a bare
    ======== Running on ... ======== line that happened to carry the URL. Nothing runs after
    uv tool install prints its executable list, so a daemon's first line is the only place
    those facts can be given. It also names the thing Ctrl-C does not do: Ctrl-C detaches and
    leaves supervised sessions running, and swemuxd --shutdown is what stops everything.

  • The Settings → Desktop integration group no longer offers to download the desktop shell,
    because there is nothing left to download. It reports whether this environment can run the
    tray and, when it cannot, the reinstall command for how this copy was installed.

Fixed

  • Turning the per-harness Agent CLI toggle off is now reported as restart-scoped, like
    its MCP and instrumentation neighbours. It was documented and rendered as needing a
    restart while the daemon classified it as hot-applied, so the response claimed an apply
    that never reached already-built adapters.

Everything in the following group came from one testing session on a clean Windows 11 machine
that is not the development host, which is the first time swe-mux had been run on one. They
share a cause: a property of the development host was written down as a fact about Windows.

  • Claude Code sessions report their lifecycle again on machines without Git Bash. The
    hook command named the interpreter in the MSYS form (/c/Users/...), which only Git Bash
    can run. Where Claude Code dispatches hooks through PowerShell instead, all eleven events
    failed with CommandNotFoundException and took status detection, history, the prompt queue
    and approvals with them - while the session kept running and looking healthy. The path is
    now written C:/Users/..., the one spelling PowerShell, Bash and cmd all execute, and it
    reaches the shell unquoted (a space is removed via the 8.3 short name, because at command
    position PowerShell reads a quoted string as a string rather than a program).
  • swemux doctor now fails when an agent session has never reported a hook. The failure
    above was silent and total, and was found by a human reading the CLI's stderr. It reports
    only sessions this daemon spawned, so a daemon restart does not flag every healthy session.
  • A prerequisite that is installed but not on PATH is no longer reported as missing.
    Detection equated "on PATH" with "installed", so a machine with Git installed and Tailscale
    installed and connected to a tailnet was told to winget install both. Tailscale's
    Windows installer never adds its directory to PATH, so that was every GUI install of it -
    and it silently disabled Tailscale Serve, tailscale cert and the direct TLS listener with
    it. There are now three states rather than two, the off-PATH remedy names PATH instead of
    an install, and detection looks in the default install locations.
  • Settings → Diagnostics has a Re-scan button and a per-tool path override. Re-scan
    re-reads PATH from Windows before looking again, because a daemon inherits its environment
    once at startup and would otherwise keep reporting a tool installed five minutes ago as
    absent, with nothing saying why.
  • Install instructions are per-platform. A Linux user missing Git was told to run
    winget and sent to a /download/win page.
  • uv is on the prerequisite checklist, since managed integrations are installed with it.
  • The Edge TTS integration installs without uv when there is a real Python to use. uv is
    still preferred and still tried first, because uv venv --python 3.12 can provide the
    interpreter as well as the environment - which is the only thing that works on a machine
    with no Python, or in the frozen desktop app where sys.executable is the bundle rather
    than a Python. A source install with neither uv nor that problem now falls back to
    python -m venv and pip, installing the same pinned version from the same index. Where
    neither is possible the refusal names both remedies instead of only naming uv, and a
    Debian machine missing python3-venv is told that specifically.
  • A Windows 11 machine without WSL stops spawning wsl.exe every 30 seconds. Windows 11
    ships that binary whether or not the subsystem is installed, so availability was a
    guaranteed false positive; the stub then blocked, because the daemon runs windowless, and
    was tree-killed at an 8s timeout on every status poll, forever. Availability is now a
    registry check and no WSL command inherits the daemon's stdin.
  • Voice setup works on Python 3.13 and 3.14. uv tool install picks the newest CPython
    on the machine, and the pinned voice closure had no wheel spaCy could load on 3.14, so
    local voice dead-ended at "no wheel this interpreter can load for: spacy". The pins now
    cover 3.12 through 3.14, CI checks the closure against each of them rather than only the
    3.12 it pins, and the refusal names the interpreter and the supported range instead of
    reading as a broken package.
  • Downloads verify TLS against the OS certificate store. The Kokoro pronunciation model
    failed with unable to get local issuer certificate against github.com on a machine whose
    browser reached the same URL: Windows fetches most roots on demand and Python's reading of
    the store only sees the ones already fetched.
  • The Edge TTS install no longer throws away 80 seconds of work to report a timeout. It
    checks it can reach PyPI before building anything, and separates "cannot connect" from
    "cannot verify". Its verification step - which imports the package and makes no network
    request at all - had a 20s budget that a first-ever import on a cold, scanned filesystem
    could not meet; it is now 120s and says what it was actually doing.

Full changelog: https://github.com/jatoran/swe-mux/blob/v0.2.0/CHANGELOG.md