LunarWing v2.1.0.0 Release - Codename Ma-ai
Ma-ai

間合い
Distance is a decision.
The blade learns when not to swing. Interrupt the storm mid-word. Steer the turn while it still breathes. Between two beats lives the strike.
There is a distance between the hand and the blade.
There is a distance between a thought and an action.
And there is a distance between an agent deciding what to do and actually doing it.
Until now, much of LunarWing’s control lived at the edges of that distance. A turn could be stopped when it reached a boundary. A conversation could be guided when it returned for another turn. A running system could be watched, but there were fewer ways to reach into the space between one decision and the next.
Ma-ai changes that.
間合い is the space, timing, and relationship between two opponents. It is not simply distance. It is the distance at which action becomes possible, and the timing at which action becomes correct.
LunarWing v2.1.0.0 brings that idea into the agent loop.
A running turn can now be interrupted while the model is still thinking or a tool is still working. Guidance can be placed into the path of an active conversation and carried forward until the next safe moment to act. Voice and vision become proper parts of the tenant lifecycle. Memory learns to degrade gracefully instead of turning uncertainty into absence.
And beneath all of it, the machinery becomes harder to fool.
The storm does not need to be stopped.
Sometimes, you simply need to change where the blade is pointed.
The space between actions
Highlights
-
Mid-turn interrupt.
/interruptcan now cancel an active LLM stream or running tool batch instead of waiting for the current step to finish. Classic chat turns receive a per-thread cancellation token, while Engine V2 propagates per-run cancellation into CodeAct, direct, and parallel tool execution. Long-running tool calls can therefore be stopped while they are still running. -
Hermes-style steer.
/steer <note>allows an operator to guide a running conversation without waiting for the turn to finish. Notes are queued at safe execution boundaries, with bounded durable storage so guidance is not silently discarded while a conversation is interrupted, approval-paused, or otherwise unable to consume it immediately. -
LunarVoice becomes a managed service. The voice sidecar now has a complete
mt-adminlifecycle, including installation, configuration, activation, deactivation, removal, model verification, tenant-specific ports, health integration, systemd user Quadlet support, Podman fallback handling, and OpenRC supervision. -
LunarVision can leave the nest. Tenants can now use an operator-managed external HTTPS vision instance instead of only the managed local sidecar. Remote origins, paths, redirects, credentials, and bearer forwarding are constrained so external vision remains inside an explicit boundary.
-
The gateway gains a face. An opt-in draggable mascot can now react to agent activity through eight canonical emotes, with idle, working, greeting, error, and queued-emote states. It remains disabled by default. Set
MASCOT_ENABLED=truewhen you want the little creature on the bridge. -
Memory learns to admit uncertainty. Mission knowledge recall now falls back through keyword, OR, type-priority, and recency paths when embeddings or strict full-text queries fail. A weak search result no longer becomes an assertion that the memory does not exist. Mission sub-agents can also resolve the structured memory writer for persistent notes.
-
The system becomes harder to impersonate. Passive completion claims such as “was written” or “was retrieved” are now detected when no actual tool result exists, prompting the agent to perform the action rather than accepting its own prose as evidence.
-
Streams tell the truth. LLM
finish_reasonnow survives completion, streaming, bridge, and proxy paths. Provider stream integrity is observed outside model text, and corrupted output is downgraded rather than treated as executable content. Per-provider stream telemetry is exposed throughllm_streams. -
Approval gates expire honestly. Pending-gate expiry is configurable through
AGENT_PENDING_GATE_EXPIRY_SECS, with safe bounds and environment-over-database precedence. When an approval expires, the paused turn can resume and deliver its wrap-up response rather than silently disappearing intoFailed. -
Coordination knowledge gets the right boundaries. XMPP room-bare JIDs can now explicitly authorize a room’s occupants to publish coordination knowledge, while user bare JIDs remain excluded from that room-wide authorization.
-
SSH remembers whom it trusted. AcceptFirst host-key pins are now durable and tenant-scoped. Concurrent first connections are serialized, malformed pin records fail closed, and removing a host revokes its persisted pin.
-
The release pipeline becomes reproducible. Protected CI now validates release contexts across the backend, test, security, WASM, Python, and shell matrix. Worker images are built through protected candidate and promotion jobs using digest-bound artifacts. Two cold builds of each worker produced identical OCI manifest digests.
-
Dependencies come home. The Rust dependency closure rooted under
ic/is now vendored and locked, including the registered WASM tools. Offline workspace checks pass against the committed vendor tree, and the vendor refresh process verifies the resulting dependency set before advisory scanning. -
ShellCheck is no longer advisory. The repository warning baseline is zero, and ShellCheck is now a blocking release validation gate.
-
The onboarding console gets real browser coverage. Playwright-based browser tests exercise provisioning, secrets, upgrades, export, import, authentication, WebSocket behavior, generated credentials, and failure rendering. The misleading
--no-tokenwarning has also been corrected. -
Small operational edges get sharpened. Shallow tenant clones are handled correctly, disabled DarkIRC installations no longer leave phantom health traffic behind, mission startup gets a cancellation-aware warmup, and the desktop live harness no longer contaminates ordinary headless CI.
Upgrading
Back up your PostgreSQL database, tenant environment files, /etc/lunarwing/ports.json, workspace state, rendered units, worker data, voice models, and channel state before upgrading.
There are no new SQL migrations in v2.1.0.0. V26__study_notes_knowledge.sql remains current, and the multi-tenant port registry remains at v16.
Rebuild the daemon and installed WASM extensions through the normal deployment path. Several channel and tool registry versions have advanced, including multica, xmpp, vision-analyze, ssh, llm-context, multica-bridge, voice-transcribe, web-search, GitLab, and Cavepony.
The ic/ dependency tree now resolves through the committed ic/vendor/ snapshot. If dependencies change, refresh the vendor tree with the repository’s documented vendor-refresh procedure and commit the resulting changes alongside the manifests and lockfiles.
The new control surface is available through the web gateway, WeeChat, XMPP, and REPL:
/interrupt stops an active turn when there is something currently running.
/steer <note> queues guidance for the next safe execution boundary, including when the conversation is interrupted or waiting for approval.
The release identifier is 2.1.0.0. LunarWing-owned Rust crates and channel packages use 2.1.0. Rust 2024 and MSRV 1.96.1 remain unchanged.
The blade does not become stronger by swinging at everything.
It becomes stronger when the hand knows when not to swing.
Kiyome washed the blade clean.
Inazuma carried it into the storm.
Ma-ai teaches it the distance.
The space between one thought and the next is no longer empty.
It is where control lives.
間合い