vtcode-core
September 14, 2026 · View on GitHub
Root AGENTS.md | Agent loop, tools, LLM, safety, UI.
Module map
core/agent/: runtime, event recording, runner, progress, harness artifacts;request_envelopefreezes each segment's prompt and ordered catalog.tools/: handlers, registry, policy, execution;ToolRegistry::new_for_schemabuilds offline metadata registries without persistent workspace policy state;output_spooler.rsowns bounded model previews and spool-reference metadata whileregistry/spool_processing.rsowns pure spool decisions/preview caps;tool_intent/activity.rsowns inspection/verification classification;read_file/batch.rsowns batch admission whileread_file.rsowns single-file semantics;registry/executors/is split intoexec_command.rs,exec_output.rs,exec_sessions.rs,exec_support.rs;grep_file.rsdelegates togrep_backend.rs;task_tracking.rsowns the renderer-independent compact task-tree formatter; workspace-aware path responses usevtcode_commons::workspace_relative_display.turn/tool_outcomes/execution_result/failure_diagnosis/keeps bounded evidence, deterministic classification, auxiliary routing, and presentation behind small internal interfaces.llm/: re-export facade; providers live invtcode-llm.exec/events.rsre-exports canonicalvtcode-exec-events::ThreadEvent;prompts/owns cached static profiles, compiled runtime guidance, and bounded resource caches.mcp/plugin_providers.rs: discovers Agent Plugin MCP servers and maps them toMcpProviderConfig../-prefixed stdiocommand/cwdare canonicalized at discovery so symlink escapes cannot bypass the plugin-root sandbox.skills/skill_policy.rsowns skill-scoped tool/network/sandbox policy;skills/executor.rsowns sub-LLM/fork execution.skills/loader.rsloadsSKILL.mdmanifests from pluginskills/*/directories into the session skill catalog; repository plugin roots are metadata-only and native loading is explicit and approval-gated.notifications/: maps important runtime events to OS/desktop alerts via dedicated call-site helpers (send_global_notification). Session completion is surfaced at session finalization in the binary (session_loop_runner/notifications.rs); turn completion inturn_loop/notifications.rs. No centralThreadEvent→notification bridge — each domain outcome owns its own call site to avoid duplicates.
Rules
- Re-export public APIs from
lib.rs; consumers must not reach into submodules, and keep constants inconfig::constantsrather than inline. Keep WebMCP transport/runtime logic invtcode-webmcp; core only owns the CLI/config facade and prompt guidance. Layer resets go throughConfigServiceso path validation, cache invalidation, and effective-config reload stay shared by CLI and TUI callers; repository policy persistence must use the repository-safe config writer. Keepexec_policyandcommand_safetyas separate policy layers. - Session event sinks are authoritative: preserve ordering, use one bounded non-blocking handoff with count/byte limits and fail-closed saturation, and await the shared one-shot drain result before reporting task success.
SessionStoreSinkwrites the canonical workspace store; recovery/final assistant messages must use the canonicalThreadEventpath rather than history-only writes. Snapshot files migrate independently through V2 while unrelated durable state remains on V1. Final session archives retain only a lightweight last-turn diagnostics block; full progress history remains checkpoint-only. Blocker archives are session-owned, path-contained, and append a durable resolution before their live pointer is cleared; archive-less runner handoffs must not claim a session-archive resume ID.ModelsManagermust read provider-scoped and legacy unscoped cache snapshots, with canonical entries taking precedence; approval and installer backoff caches must likewise recover legacy files. - Trajectory logging is best effort: retain line/byte bounds and expose drops/failures through diagnostics. Spool references are consumed through
SpooledOutputReference; binary consumers must not reopen spool paths to reconstruct previews. Provider-facing tool previews share a planning-aware per-turn budget (32 KiB execution, 96 KiB planning viaturn_preview_budget_bytes); exhausted previews retain bounded scalar outcome/control metadata, record suppression diagnostics, and never invite equivalent retry calls; complete spool output is retained only for the current-session viewer. Direct and interceptedapply_patchmust validate the turn cwd and every target against the session workspace with symlink-aware containment before mutation.
Workflows
- Add tools under
tools/, register/classify them, wire them intocore/agent/; approved-plan task trackers deduplicate normalized step descriptions while preserving first-seen order, approval must fail closed if the tracker cannot be persisted, and plan artifacts must validate concrete targets plus command/observable verification markers before writing (leading shell env assignments are allowed only before a concrete command; lists need at least one concrete target; bracket lists split on commas outside single/double quotes). Add providers withadding-llm-providersand update model enumeration, presets, and thellm/providersfacade. NVIDIA-style first-class providers also need startup defaults, the secret enum, lightweight routing, and generated docs metadata; gateway providers may additionally need explicit route pass-through validation. Custom provider registration stays in the factory and delegates protocol selection to the profile-aware router; do not add arbitrary custom names to the finiteProviderenum.
Gotchas
- Import
RetryPolicyCoreExtfor domain retry methods; budget decisions belong tollm/usage_cost.rsandBudgetStatus::classify, not call sites. - Plugin MCP
command/cwdstarting with./are canonicalized and containment-checked byvtcode_agent_plugins::validate_plugin_relativebefore spawn. Never re-resolve them relative to the working directory at spawn time — that defeats the containment check. - Compaction preserves conversation and starts a new immutable request segment before replacing history;
context_reset.rsintentionally discards it. Automatic thresholds use the effective provider/session budget minus reserved output, and explicit harness thresholds are clamped to that budget;effective_context_budgetis the shared runtime/preflight/status denominator.AgentSessionState.messagesisArc<Vec<Message>>; mutate viamessages_mut()/Arc::make_mutso request and continuation histories stay shared. Request assembly should keep normalized history shared too; editor/few-shot injection and provider compaction are the intentional copy boundaries. core::agent::state::normalize_history_for_requestis request-only and idempotent: repair tool-result pairing/order for the provider wire without mutating durable session history; retain the borrowed fast path for clean histories.- Workspace-controlled lifecycle hook content (
vtcode.toml/.vtcodelayers or workspace agent-spec hooks) gates the whole engine: nothing spawns until the exact command-set digest is approved. Build engines withnew_with_session_gated, restore persisted approvals withrestore_workspace_hook_approval, and never add a bypass;new/new_with_sessionare test-only. - Async plugin, skill, file-tool, planning, persistent-memory, durable-scheduler, prompt-resource cache-miss, context-reset manifest, and trajectory setup paths must use Tokio filesystem APIs or
spawn_blockingfor recursive/synchronous scans, record loading, claim files, persistence, or Git work; registry workspace settings, including persistent-memory config, are startup snapshots. Global user paths come from oneVtCodePathssnapshot; legacy and paged text reads share the bounded line reader. - Evaluator
generalization_notesare bounded, validated, task-scoped evidence; replans must preserve scopes and add falsifiers to the tracker without promoting notes to global memory.SessionProgressSinkcoalesces snapshots through a bounded writer, so progress mutations must not perform synchronous filesystem I/O. SessionToolCatalogprojection caches are private and lazy per entry/documentation mode; rebuild the catalog when registrations change. Basic directory-list caches are keyed by canonical workspace and response shape.TerminalAppLauncher::launch_editor_target_non_waitingis for existing-file GUI opens; preserve adapter-specific reuse/location flags and keep temporary-file/editflows on the waiting API.- Token/catalog deferral thresholds are correct behavior; warn only when deferral is disabled but beneficial. Shell safety must preserve raw command text when classifying dynamic syntax; activity and read-only intent share the static shell parser, allowing compound sequences only when every segment is independently read-only while dynamic or unknown shapes fail closed as mutating; keep optional SQLite on rusqlite 0.39 until stable cfg_select support is available.
web_fetchaccepts remote HTTP(S) URLs only; local reads must useread_file/unified_file.AnsiRendererowns the session-local tool-summary display mode; Markdown table widths must be reduced for transcript indentation and framing before rendering. Compact mode groups only contiguous successful command calls; PTY live previews stay bounded while complete command output is retained in the current-session viewer, and mergedoutput/stream aliases must not duplicate payloads. Active names stay read-only;write_stdin/apply_patchremain blocked while internal plan persistence is available. Pipe/PTy and MCP stdio children inherit filtered environment policy; use the sandbox-aware launch APIs rather than bypassing them. Batch file ranges remain under the absolute line cap, and duplicate tool calls may batch only after preflight marks each call parallel-safe; unified and runner dispatch honoragent.harness.max_parallel_tool_calls. Persistent-memory remember planning may receive only one explicitly selected immediate assistant reply for deictic requests; keep that reference separate from supplemental answers, tool output, and wider conversation history, and preserve planner validation, confirmation, and post-write candidate read-back gates.- Read-only shell commands targeting
.vtcode/context/tool_outputs/must setno_spoolso inspecting a spool never creates a recursive model-visible spool reference. Registryapply_patchandwrite_fileresults include bounded canonical diff previews (with legacy compatibility fields); keep lifecycle payloads and TUI rendering paths visible when changing that response shape. Task-trackerfiles,outcome, andverifyremain structured metadata; compact view rows must not reintroduce them as visible detail lines. Planning prompt guidance is part of the runtime contract: keep plan steps concrete and verifiable, omit unused optionalcode_searchfilters (neverpath: ""), reserve<plan>for approval artifacts while structured reasoning uses its distinct marker, require one plan block without policy echo, and keep rejected drafts in assistant history. Planning empty-response recovery allows one strict tool-free synthesis after two empties; failure is a resumable blocked handoff, never another interactive prompt. Live-preview queue pressure must remain visible through bounded coalesced diagnostics; compact PTY calls suppress transient live rows, expanded calls keep bounded previews, and complete command output stays in the current-session viewer. User-facing progress prompts may offer concise phase updates when useful and must finish with a standalone evidence/verification recap without narrating calls or hidden reasoning; structured tool-call events are the status source of truth. Terminal OSC palette probes must wait for all requested replies before their settle window; failure-like results retain bounded evidence and attach deterministic or lightweight-modeldiagnosisdata before tool-free recovery; collapsed output uses one provider-neutral typed turn-scoped marker after tool results, with Anthropicclear_atonly on eligible wires and ordinary system/history mapping elsewhere; update prompt golden/compactness tests with changes. Skipped/suppressed diff previews keep stablereasoncodes; renderdiff_preview_user_messageinstead of the code.