Foundation calls CreateProcessW with CREATE_UNICODE_ENVIRONMENT and
nothing else, and offers no way to add to that. The app has no
console of its own, so every console child it started -- an
emulator, qemu-img, the agent CLI -- was given a fresh command
prompt to look at.
Spawn through ChildProcess instead, which asks for CREATE_NO_WINDOW
on Windows and is Process everywhere else.
Yield api_retry events as live notices so model overload is
visible instead of a silent spinner, and fall back to the
streamed error detail when claude exits with empty stderr.
Console widgets get an appendImage / respond.image API on the
agent. read_widget_state surfaces image entries as attachments
scaled to at most max_dimension pixels (default 1568) on the
longest edge. Anthropic nests image blocks inside tool_result;
OpenAI gets a synthetic follow-up user message. The host scales
via CoreImage on macOS and GdkPixbuf on GTK.
LLMProviderCapabilities and LLMModelInfo each hold a
Set<LLMCapability> with a supports(_:) accessor. Adding a
capability is one enum case plus an entry in each
provider's supported set.
Fetch models at runtime where supported (OpenAI, local
OpenAI-compatible). Static lists for Anthropic and Claude
Code; the OpenAI list was already drifting.
Add reasoningEffortOptions capability. Claude Code exposes
[auto, low, medium, high, xhigh, max] and routes the choice
to its --effort flag. LLMTurnRequest, Mission, the executor
and the mission schema all carry reasoningEffort end to end.
suggestedModels is now async/throws and takes apiKey and
baseURL so dynamic providers can authenticate and target a
caller-supplied endpoint.
MCPServer.stop is synchronous; awaiting it produced a
"no async operations occur within await" warning. Call it
directly in Engine.disableExternalMCPServer, and from
ClaudeCodeProvider's MCPServerHandle bounce through
MainActor.run since the actor itself is non-isolated.
A new title column carries a short label generated in
parallel with mission start. Each LLMProviderDescriptor
declares a summarizationModelID so the pass runs on the
mission's own backend (Haiku for Anthropic and Claude
Code, gpt-5-mini for OpenAI, llama3.2:3b locally). The
instruction sits in the user message to dodge Claude
Code's prompt layering and asks for two to four punchy
words. Sidebar shows title or goal; header keeps the
full goal under the title.
claude --include-partial-messages only streams deltas for
the model's final response, but assistant events arrive for
every intermediate message. Preferring streamedText dropped
the model's opening narration before any tool calls. Use
assistantText whenever it's non-empty so the persisted
turn carries the entire response.
Foundation's Process is unavailable on iOS-family
platforms, so gate ClaudeCodeProvider behind macOS,
Linux, and Windows. The Engine register call is
gated to match.
- Engine and ClaudeCodeProvider gates now activate whenever
Network or CSoup is importable, so the libsoup transport
actually wires up at runtime on Linux/Windows.
- Drop OpaquePointer detours; libsoup's typed pointers and
guint port/status arguments compile cleanly now.
- Replace the variadic soup_server_new(NULL) call with a tiny
shim — Swift's Clang importer marks variadics unavailable.
availableData is synchronous and froze the main actor while
claude initialized. That starved the MCPServer dispatch tasks
queued on the same actor, so claude saw a non-responsive MCP
endpoint and reported "tools haven't come online yet".
Reading via readabilityHandler -> AsyncStream keeps the actor
free to service MCP traffic.
The Network-framework MCP server is Apple-only. Wrap the
listener, the Engine state and the ClaudeCodeProvider MCP
branch behind canImport(Network) so LumaCore still builds on
Linux/Windows. A libsoup-backed implementation lands next.
While here: echo the client's protocolVersion in initialize
and announce tools.listChanged so claude's MCP client accepts
the handshake.
App-bundle launches inherit a bare PATH; inject the usual
install dirs (~/.local/bin, /opt/homebrew/bin, etc.) into
the spawned environment so /usr/bin/env resolves claude.
LLMProviderError gains LocalizedError so failures stop
surfacing as "error 0".
Tool calls from Claude Code via MCP suspend on a checked
continuation when the spec is non-observe. Engine routes
approve/reject to the active MCPServer to resume execution
or send a refusal back to Claude Code.
ClaudeCodeProvider subprocesses claude in --print mode with an
in-process HTTP MCP server on loopback exposing the tool catalog.
Tool calls persist as MissionAction rows so the Action Queue
stays populated.