v0.3.4
Veröffentlicht am .
Paneflow v0.3.4 — Agent CLI hardening: security, robustness, memory, performance
The largest hardening drop yet. Two back-to-back 4-axis audits (memory, security, performance, robustness) on the CLI-agent subsystem, shipped as two PRDs landing together: prd-agents-hardening-2026-Q3 (19 stories, closing the post-visual-parity audit) and prd-cli-hardening-followup-2026-Q3 (30 stories across 6 epics, closing the 4 deferred follow-ups plus 26 fresh findings). Every fix is grounded in a file:line audit citation, not conjecture. No new .unwrap() / .expect(), no new abstraction layers — surgical fixes through the project's panic = deny / unwrap_used = warn clippy gate.
Why it matters: Paneflow is the only AI-agents IDE built in pure Rust + GPUI, and the pitch is "Rust native = leaner than the wrapper." This release makes that honest — bounded memory on all-day sessions, zero main-thread panics under resource exhaustion, and a locked-down IPC surface before more external integrations come online.
Memory — bounded footprint on long sessions
DiffSnapshot.old_textfreed on review completion. A 500-turn refactor session was retaining 10–100 MB of pre-edit file content for already-reviewed edits. The diff body is now dropped after review and the renderer short-circuits to a[diff body cleared after review, N lines]placeholder.- Per-tool-call UI state pruned on terminal status.
tool_label_markdownanddiff_scroll_handlesonly pruned on Keep-All / Reject-All, so Read / Search / Execute tool calls leakedEntity<Markdown>GPUI registry entries for the whole thread lifetime. They are now purged as each tool call reaches a terminal state. - Session cache capped at 10 LRU entries;
pending_promptsqueue bounded by size + byte budget.
Robustness — no panics, no silent error sinks
- IPC thread spawn no longer panics the app.
ipc.rspreviously.expect()-ed the spawn; underRLIMIT_NPROC/EAGAINthat killed every active agent thread. It now degrades gracefully. wait_for_exitbounded with a 30 s deadline — aSIGKILLrace that missedwaitpidused to leak one blocking-pool thread (max 128) perterminal/create.RuntimeEventchannel bounded at capacity 256 with producer back-pressure (migrated totokio::sync::mpsc).- Six silent
Err(Closed)sinks now logged across the title summarizer and composer — a window closing mid-task no longer makes a file insertion or generated title vanish without a breadcrumb. - Mutex-poison recovery and NTP backwards-step sentinels added to the session cache / relative-time path.
Security — IPC surface and parser bounds
- JSONL parsers capped at 64 KiB per line across the Claude / Codex / OpenCode / agent session readers — a malicious 500 MB single-line JSONL planted in
~/.claude/projects/<slug>/no longer OOMs the process. - Rust 1.85 env-race fixed.
scrub_claudecode_envmoved tomain()before anythread::spawn; the previousunsafe remove_varfrom a non-main thread raced concurrentgetenvin the tokio / smol / IPC threads since Rust 1.85. surface.send_textblast radius documented + gated behind an opt-in flag — it was an undocumented same-UID RCE primitive.- API-key-shaped strings redacted before
trace_wire_lineso*_API_KEY=…prefix tokens stop landing inpaneflow-debug.logunderRUST_LOG=trace. workspace.createcwd canonicalized and non-directories rejected;file_opsreads bounded with line streaming + a max-bytes cap.- Kill-on-parent-death hardened cross-platform —
PR_SET_PDEATHSIGin thepaneflow-shimpre_execon Linux (Windows JobObject already shipped, macOS no-op), and the shim self-exclusion now uses Unix(dev, ino)instead of a dir-string compare.
Performance — streaming hot paths
Markdown::appendO(n²) root cause fixed. Streaming previously rebuiltSharedString::new(source.to_string() + text)every tick — 30–50% main-thread CPU on 5 concurrent agents. Fixed via theArthurDEV44/zed@paneflow/markdown-append-fixfork (one additiveString-buffer patch oncrates/markdown, ~38× throughput on the streaming path; 9 downstream Zed consumers compile unchanged). Reverts to upstream once the PR merges.highlight_codememoized by(language, content-hash)— syntect was running synchronously insideRender::renderat 3–8 ms per visible code block per frame.compute_activity_stateis now O(1) (incremental counters, was a linear scan), markdown element IDs cached at parse time, runtime command channel migrated off the per-commandspawn_blocking+Mutex+ join pattern, dirty-flag persistence incollect_persisted_items.
Quality gates & tooling
cargo denywired into CI — a daily security-audit cron (audit.yml) opens an issue when the lockfile gains a new advisory overnight, complementing the blocking PR-gate. Two known transitive advisories (rsaMarvin sidechannel via LSP TLS, not exposed;async-stddiscontinued, not in the current fork tree) are whitelisted with explicit rationale.- Criterion baselines added for
blob_compress(zstd roundtrip on the persist path),markdown_append, andhighlight_codeto catch perf regressions on those exact hot paths. - Heaptrack runbook documented for the 5-agent streaming scenario (see
tasks/heaptrack-runbook.md).
Breaking: claude_code_bypass_permissions now defaults to false (was true). The Agents panel asks before each Claude Code tool call on a fresh install — the previous default was a latent vulnerability. Set it back to true in config if you scripted around the old behavior.
Build note: this release builds against the ArthurDEV44/zed@paneflow/markdown-append-fix fork (pinned by exact sha in Cargo.lock) rather than upstream zed-industries/zed, for the Markdown::append fix. It reverts to an upstream rev once the PR merges.
Notes live aus dem GitHub-Release.