vtcode Binary Gotchas
August 8, 2026 ยท View on GitHub
This guide preserves detailed maintainer notes for the binary crate. Keep
src/AGENTS.md concise; use this page when changing the runloop, update path,
allocator, or request assembly.
Startup, updates, and allocation
- Standalone updates own asset selection, checksum verification, safe archive extraction, and
self_replace; keep managed-install guidance separate and keep inline TUI downloads quiet. main_helpershandles runtime relaunch context; do not duplicate initialization logic inmain.rs.- Allocator memory pinning: vtcode's bursty/sparse Tokio workload (semaphore-capped
JoinSetfan-out followed by idle workers) can leave bothmimallocandglibcRSS flat after a burst because frees are stranded on cross-thread lists until later allocation activity.jemallocreturns memory while idle only whenbackground_threadis active; on macOS its build reportsbackground_thread currently supports pthread onlyand behaves like mimalloc. On Linux containers it can reclaim memory. Measure withvtcode bench-allocatorbefore changing the default. load_dotenv()must run before config load so.envAPI keys are available.- Provider noise (for example
]<]minimax[>[) is stripped centrally inturn::provider_noise; stream-level harmony and MiniMax sanitization lives instream_sanitization::StreamSanitizer. Do not re-implement it inline.
Tool-budget and recovery contracts
- Wall-clock and tool-call budget exhaustion share one contract: emit the full policy message once, compact stubs for later batch calls, then one synthesis directive via
flush_budget_synthesis_directivesafter the tool batch. Do not break the turn asBlocked, because that skips synthesis. The flush armsswitch_to_tool_free_recovery()so the next request removes tool definitions at the API level. tool_budget_exhausted_emittedparticipates in the plan-modemark_recovery_exhaustedgates. The preflight circuit breaker inturn/tool_outcomes/handlers/mod.rsfollows the sameContinueplus deferred synthesis path viapreflight_circuit_recovery_pendingandflush_preflight_circuit_recovery; never returnBreak(Blocked)for an approved-plan build.- During tool-free recovery, do not inject
request_user_input; it violates the recovery contract. Plan-aware fallback must preserve interview state, while exhausted budget or recovery caps conclude with the user-facing planning notice instead of re-forcing research or emitting a final directive with no following model call. - The interview-denied recovery fallback must distinguish "no draft produced" from "draft persisted."
PLANNING_RECOVERY_SYNTHESIS_FALLBACK_NO_INTERVIEWpromises "Review the plan below" and offersyes/implement/no/editโ those choices dead-end without a persisted plan and contradict the appendedPLANNING_WORKFLOW_NO_APPROVAL_READY_PLAN_HINT. Whenpersisted_plan_readyis false, usePLANNING_INTERVIEW_DENIED_NO_DRAFT_NOTICEinstead (turn_902). - Permanent
request_user_inputdenial is distinct from user cancellation. Mark denial from both execution failure and permission-flow denial, suppress the tool for the rest of the session, and route text replies through the shared planning intent classifier.
Request assembly and planning
turn_processing/llm_request/uses contract-carryingpub(super)submodules (snapshot,tool_shaping,context_management,response_chain,prompt_assembly,prompt_sections, andprompt_runtime). Go throughmod.rsexports.- Prompt section order in
prompt_assembly::build_prompt_outputis provider-cache-sensitive. Hosted Anthropic/OpenAI payloads retain deferred tool definitions; only ClientLocal policy omits them.metrics.rsemits the per-requesttoken_budget_breakdown; prompt-cache diagnostics remain inSessionStats. - Plans stay compact/spec-like:
PLANNING_WORKFLOW_PLAN_QUALITY_LINErequires roughly 1500 tokens withAction -> files/symbols -> verify:steps and file/symbol references. The truncation recovery prompt is bounded byMAX_PLAN_SYNTHESIS_CONDENSE_ATTEMPTS. - Planning research scales to request complexity; the wall-clock budget is the backstop, not a replacement hard tool-count cap.
effective_max_tool_calls_for_turnand mid-turn config reapplication preserve the shared planning floor. - Approval phrases are classified by
detect_planning_intentand must restore a write-capable primary agent, preserveauto_accept, create the tracker, and apply the approved-plan tool-call floor. Direct and queued approval paths share this boundary. - Emit
plan.approval.requestedandplan.approval.resolvedfor every decision using the canonicalThreadEventcontract and preserve Open Responses parity. - Enter/exit phrase literals live in
vtcode_core::planningand are shared by the runloop and Codex bridge; add a phrase once, never fork consumer-specific aliases. - Tool-summary renderers receive
ToolSummaryRenderContextat their public render entry points; pure helpers may remainOption<&Path>-driven internally. - Compact tool-summary grouping is session-local and batch-scoped; expanded mode remains the default, and failures, warnings, PTY output, diffs, and result bodies stay ungrouped.
- Completed turns publish a non-empty final assistant response through both renderer and
ThreadEventharness paths. Recovery fallbacks remain visible but produce a blocked outcome; approved-plan summaries retain changed files, verification, and blockers.
For prompt/runtime source boundaries, see runtime guidance.