This document establishes canonical names for the Shofer extension's UI components, architectural concepts, data types, and protocols. Use these names when communicating about the codebase so that references are unambiguous.
- UI Components — Chat Area
- UI Components — Task Management
- UI Components — VS Code Panel Title Bar
- UI Components — Sidebar & Navigation
- UI Components — Panels & Overlays
- Architecture — Extension Host (Backend)
- Architecture — Webview (Frontend)
- Data Types & Schemas
- IPC Protocol
- Tools — Canonical Names
- Tool Groups (Categories)
- Modes
- Task States & Lifecycle
- Special Files & Directories
- API Provider Concepts
- Private Tool Provider System
- Telemetry Concepts
- Context Window Data Flow
- System Prompt Architecture
- Configuration Concepts
The chat area is the primary interface shown when a task is active. It occupies the main area of the Shofer sidebar or editor tab.
| Canonical Name | File | Description |
|---|---|---|
| ChatView | ChatView.tsx |
The main chat container. Owns message history (shoferMessages), scroll position, image state, and dialog state. |
| ChatTextArea | ChatTextArea.tsx |
The chat input bar at the bottom. Contains the text input, Send/Stop buttons, and all toolbar controls — ModeSelector, ApiConfigSelector, AutoApproveDropdown, CommandsButton, SkillsButton and IndexingStatusBadge — along with any plugin chat-input-toolbar contributions (the worktrees branch chip, the Live Memory status badge — see LiveMemoryStatusBadge). |
| ChatRow | ChatRow.tsx |
A single message row rendered in the chat history. Handles all message types: say, ask, tool calls, reasoning, etc. |
| TaskHeader | TaskHeader.tsx |
The header bar above the chat messages. Shows task name, token usage, cost, context window bar, active wall-clock time, and todo list. When a task is in progress (isRunning is true) the header container gains an animated shimmer outline with interior glow (task-header-shimmer CSS class) — a thin gradient sweep around the container with a soft inset fill — providing a "live" Copilot-style visual indicator (static outline under prefers-reduced-motion). |
| ModeSelector | ModeSelector.tsx |
Dropdown in the chat input bar for selecting/switching the current mode (e.g., Code, Architect, Debug). |
| ApiConfigSelector | ApiConfigSelector.tsx |
Dropdown in the chat input bar for choosing the API provider profile (e.g., "openrouter", "deepseek"). |
| AutoApproveDropdown | AutoApproveDropdown.tsx |
Dropdown in the chat input bar that shows auto-approval category toggles scoped to the current mode. |
| CommandsButton | CommandsButton.tsx |
Button (⚡) in the chat input bar that opens a popover listing slash commands grouped by source (Project, Global, Built-in). Clicking a command appends it to the chat input via insertTextIntoTextarea. |
| SkillsButton | SkillsButton.tsx |
Button (🎓) in the chat input bar that opens a popover showing loaded skills (✓ checkmark) and available skills grouped by mode. Clicking inserts Use the <name> skill via insertTextIntoTextarea. |
| worktree chip | indicator.tsx |
The basics plugin's worktrees feature's chat-input-toolbar contribution: shows the branch the task runs on; its popover carries git status (ahead/behind, merge readiness), the other worktrees to pick from, creation progress (worktreeinclude copy + submodule init) and a "Create new worktree…" entry. |
| IndexingStatusBadge | IndexingStatusBadge.tsx |
Badge in the chat input bar showing code index status (Standby/Indexing/Indexed/Error). |
| LiveMemoryStatusBadge | badge.tsx |
Chat-input-bar badge (chat-bubble icon + colored status dot) showing the Live Memory agent state (Standby/Ready/Busy/Error), with context-fill/queue detail in the tooltip. Now a plugin chat-input-toolbar UI contribution of the bundled live-memory plugin (was a built-in webview component), fed by the same ctx.ui state stream as the panel. |
| ContextWindowProgress | ContextWindowProgress.tsx |
Horizontal bar in TaskHeader showing how much of the model's context window is used. |
| ReasoningBlock | ReasoningBlock.tsx |
A collapsible block showing the model's reasoning/thinking content (streamed before the final response). |
| Markdown | Markdown.tsx |
Markdown-to-HTML renderer used for all message content. Handles code blocks, tables, and syntax highlighting. |
| ProgressIndicator | ProgressIndicator.tsx |
"Tool preparing…" spinner shown while the LLM streams tool call arguments. |
| ErrorRow | ErrorRow.tsx |
Chat row rendered for errors. |
| WarningRow | WarningRow.tsx |
Chat row rendered for warnings (e.g., retired provider, profile violations). |
| ProfileViolationWarning | ProfileViolationWarning.tsx |
Warning row shown when profile thresholds are violated (tool count, cost, requests). |
| TodoListDisplay | TodoListDisplay.tsx |
Todo list rendered in the TaskHeader, showing current task's todos with completion toggles. |
| TodoChangeDisplay | TodoChangeDisplay.tsx |
Inline display of a todo list change (add/remove/update) as a chat message. |
| Mention | Mention.tsx |
Renders @file/path and @folder/path mentions as clickable links that open the referenced resource. |
| ContextMenu | ContextMenu.tsx |
Autocomplete/mention suggestion dropdown triggered by typing @ in the chat input. |
| Thumbnails | Thumbnails.tsx |
Image thumbnail strip shown above the chat input when images are attached. Supports delete. |
| ImageViewer | ImageViewer.tsx |
Full-size modal image viewer with zoom, copy, save, and action buttons. Used for generated images. |
| Announcement | Announcement.tsx |
Dismissible announcement banner shown at the top of ChatView. |
| useScrollLifecycle | useScrollLifecycle.ts |
React hook managing all chat scroll state and logic. Implements a three-phase state machine (HYDRATING_PINNED_TO_BOTTOM, ANCHORED_FOLLOWING, USER_BROWSING_HISTORY), the scroll-to-bottom button visibility, row-height-change response, and user-intent detection (wheel, pointer, keyboard). |
| Scroll-to-bottom button | (rendered inside ChatView.tsx) |
The codicon-chevron-down button that appears when the user scrolls up during streaming. Clicking it re-engages sticky follow and scrolls to the latest message. |
| Term | Description |
|---|---|
selectedImages |
State array of base64 data URLs managed in ChatView.tsx and passed to ChatTextArea.tsx. Capped at MAX_IMAGES_PER_MESSAGE. |
droppedContextFiles |
React state (useState) in ChatView.tsx holding Array<{ path: string, isFile: boolean }>. Populated by three drop paths (native TreeView via addContextFiles IPC, ChatView root handleWebviewDrop, ChatTextArea handleDrop via onContextFilesDropped callback). Rendered as removable tags above the chat input; converted to @/path mentions on Send. Scoped per task via taskScopedState so file tags don't leak across task switches. |
shouldDisableImages |
Boolean computed in ChatView.tsx as !model?.supportsImages || selectedImages.length >= MAX_IMAGES_PER_MESSAGE. Passed to ChatTextArea to gate paste, drop, and image button. |
MAX_IMAGES_PER_MESSAGE |
Constant (20) exported from ChatView.tsx. Matches Anthropic's image-per-message limit. |
Components related to viewing, switching, and managing multiple tasks.
| Canonical Name | File | Description |
|---|---|---|
| TaskSelector | TaskSelector.tsx |
Dropdown in TaskHeader that lists all tasks with state indicators (colored dots), notification badges, parent-child hierarchy, archive toggle, and pin support. |
| TaskActions | TaskActions.tsx |
Action buttons in the TaskHeader: archive, pin, export (JSON/Markdown), delete. |
| TaskNotification | TaskNotification.tsx |
Popup/toast notification shown when a background task needs input, completes, or errors. |
| QueuedMessages | QueuedMessages.tsx |
Collapsible section showing queued messages waiting to be sent (when task is busy processing). |
| HistoryView | HistoryView.tsx |
Full task history view with search, batch delete, copy, and export. |
| HistoryPreview | HistoryPreview.tsx |
Collapsed preview of recent task history shown when no task is active. |
| TaskItem | TaskItem.tsx |
Single task row in HistoryView. |
| TaskGroupItem | TaskGroupItem.tsx |
Grouping row in HistoryView (e.g., "Today", "Yesterday"). |
| SubtaskRow | SubtaskRow.tsx |
Indented subtask row in HistoryView. |
| SubtaskCollapsibleRow | SubtaskCollapsibleRow.tsx |
Collapsible parent row showing its subtasks underneath. |
| BatchDeleteTaskDialog | BatchDeleteTaskDialog.tsx |
Confirmation dialog for batch-deleting tasks. |
| DeleteTaskDialog | DeleteTaskDialog.tsx |
Confirmation dialog for deleting a single task. |
| MessageRewindDialog | MessageRewindDialog.tsx |
Dialog confirming deletion/edit of a message, offering to roll back plugin-held state (e.g. the workspace) when a restorable marker follows it. |
| EditMessageDialog | MessageModificationConfirmationDialog.tsx |
Dialog for editing a user message. |
| BudgetLimitDialog | BudgetLimitDialog.tsx |
Dialog for configuring a per-task USD cost limit (max amount + action on exceed). |
| SessionSearch | SessionSearch.tsx |
Search bar (Ctrl+F) for finding text within the current task's message history. Navigates to matches via virtuosoRef.scrollToIndex directly, bypassing the scroll lifecycle phase transitions. |
These are the native VS Code icon buttons rendered by VS Code itself in the title bar of the Shofer panel — not React components inside the webview. They are declared in src/package.json under contributes.menus.view/title (sidebar) and contributes.menus.editor/title (tab panel), and backed by commands registered in src/activate/registerCommands.ts.
There are two display tools:
- Navigation buttons (
group: "navigation@N") — shown as icons directly in the title bar, left-to-right in ascendingNorder. - Overflow buttons (
group: "overflow@N") — hidden inside the⋯("More Actions…") dropdown.
| Canonical Name | Command ID | Icon | Group | Description |
|---|---|---|---|---|
| Plus button | shofer.plusButtonClicked |
$(add) |
navigation@1 |
Opens LauncherView (the mode cards) by posting action: "newMenuButtonClicked". It toggles — a second click returns to chat. The current task is left untouched until the user actually picks a mode. |
| Tasks button | shofer.tasksButtonClicked |
$(list-tree) |
navigation@2 |
Opens the parallel-tasks drawer inside the webview. |
| Settings button | shofer.settingsButtonClicked |
$(settings-gear) |
navigation@3 |
Navigates to SettingsView inside the webview. |
| History button | shofer.historyButtonClicked |
$(history) |
overflow@1 |
Navigates to HistoryView inside the webview. |
| Popout button | shofer.popoutButtonClicked |
$(link-external) |
overflow@2 |
Opens Shofer in a new editor tab (openShoferInNewTab). |
Quick reference for requests:
- "Add a button to the VS Code title bar" → add a
contributes.menus.view/title+editor/titleentry and a newCommandId.- "Put it next to the Plus/Settings icons" → use a
navigation@Ngroup.- "Put it in the
⋯menu" → use anoverflow@Ngroup.- Do not confuse these with the React toolbar inside ChatTextArea (the webview input bar), which contains ModeSelector, ApiConfigSelector, AutoApproveDropdown, CommandsButton, SkillsButton, etc.
Components in the Shofer sidebar (or editor tab header) for top-level navigation.
| Canonical Name | File | Description |
|---|---|---|
| SettingsView | SettingsView.tsx |
The settings panel with sections for API configs, auto-approval, modes, tools, etc. |
| WelcomeView | WelcomeViewProvider.tsx |
Welcome/splash screen shown on first launch or when no task history exists. |
| LauncherView | LauncherView.tsx |
Full-panel launch surface shown when the user presses the Plus button ($(add)), replacing the chat surface while active. Renders one card per available mode (built-in + custom); clicking a card posts launchTask and the host switches back to the chat surface. |
The top-level tabs are: chat, history, settings, launcher.
| Canonical Name | File | Description |
|---|---|---|
| File Changes panel | plugins/basics/ui/panel.tsx |
Collapsible panel showing files modified by the current task, with Accept/Revert per file and Accept All/Revert All. Contributed by the basics plugin's file-changes feature into the chat-footer UI region. |
| CodeIndexPopover | CodeIndexPopover.tsx |
Popover showing code indexing status and controls. |
| LiveMemoryPopover | (removed) | The built-in badge's click-popover (status + actions). Removed in the plugin conversion — the plugin LiveMemoryStatusBadge surfaces status via tooltip; actions live in the sidebar panel and the /live-memory:* commands. |
| LiveMemoryChatPanel | panel.tsx |
The Live Memory chat panel that streams the agent's conversation + state live. Now a plugin sidebar-panel UI contribution (mounted as a collapsible drawer in the chat view via PluginSidebarPanel.tsx); was the built-in LiveMemoryChatProvider WebviewPanel. Renders typed AgentMessageParts (text markdown, reasoning collapsible, tool_call expandable with in-progress spinner) from the ctx.ui state stream. |
| BatchDiffApproval | BatchDiffApproval.tsx |
UI for reviewing and approving multiple diffs as a batch. |
| BatchFilePermission | BatchFilePermission.tsx |
UI for granting write permission to multiple files at once. |
| BatchListFilesPermission | BatchListFilesPermission.tsx |
UI for granting read permission to multiple directories at once. |
These components run in the VS Code extension host (Node.js process).
| Canonical Name | File | Description |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | --------- | ------------- | ----------------------------------------------------------------------- |
| Task | Task.ts | The main task execution class. Runs the LLM conversation loop, executes tools, emits lifecycle events (TaskStarted, TaskInteractive, TaskIdle, TaskCompleted). |
| ShoferProvider | ShoferProvider.ts | The VS Code WebviewViewProvider. Manages the task stack, creates/destroys Task instances, posts state to the webview, handles parallel task operations, and routes plugin-UI requests to the host that owns the focused task (resolvePluginUiRequest). |
| TaskManager | TaskManager.ts | Manages parallel task execution. Tracks ManagedTask instances, lifecycle state, and background task notifications. Exposes registerBackgroundTask(), getManagedTaskInstance(), and getManagedTask(). |
| TaskManager.registerBackgroundTask | TaskManager.ts | Registers a child Task instance as a managed background task. Called by NewTaskTool.execute() for every child it spawns. Requires assertRestored(). |
| TaskManager.getManagedTaskInstance | TaskManager.ts | Returns the live Task instance for a given targetTaskId from the activeTasks map, or undefined if not running. |
| Task.abortBackgroundChildren | Task.ts | Iterates backgroundChildren, fetches each live instance from TaskManager, and calls abortTask(true). Called by AttemptCompletionTool and Task.abortTask(). |
| Task.cleanupBackgroundChildren | Task.ts | Reaps dead children whose instances are no longer alive in TaskManager, consulting persisted history for final status. |
| Task.didExecuteAttemptCompletion | Task.ts | Boolean flag ensuring only the first attempt_completion executes when the LLM streams multiple such calls in a single response after delegation resume. |
| Task._softCancelForQueuedMessage | Task.ts | Private boolean flag set by cancelAndProcessQueuedMessages before aborting the streaming loop. When true, the stream catch block breaks instead of calling abortTask(), preserving the Task instance so it can restart the loop with the dequeued message. |
| Task._taskAbortController | Task.ts | Task-lifetime AbortController. Aborted by abortTask() (Stop) and cancelAndProcessQueuedMessages() (Send Now). Exposed as task.abortSignal. Replaced with a fresh controller by cancelAndProcessQueuedMessages before restarting the loop so subsequent tool calls get a live signal. |
| Task.abortTask() | Task.ts | Destructive cancellation method. Sets this.abort = true then aborts _taskAbortController. Used by user Stop, budget-limit "kill", and stream failures. Also aborts background children and async MCP calls. |
| Task.currentRequestAbortController | Task.ts | Per-request AbortController scoped to the current LLM API call. Aborted by cancelAndProcessQueuedMessages before the task-lifetime controller, so the in-flight HTTP request is cancelled independently of MCP tool calls. |
| runMcpToolCall | use-mcp-shared.ts | Shared helper that calls mcpHub.callTool() with signal ?? task.abortSignal. The canonical call site where the task abort signal is threaded into MCP tool execution. Used by UseMcpToolTool and the new-task subtask tool path. |
| canStop | ChatView.tsx | Computed boolean in ChatView that determines Stop button visibility. Checks three conditions: isStreaming, currentTaskRuntimeState?.lifecycle === "running" (covers auto-approved tool execution), and shoferAsk !== undefined (excludes completion_result / resume_task / resume_completed_task). Broader than isStreaming alone. |
| currentTaskRuntimeState | ChatView.tsx | useMemo in ChatView that looks up the current task's state from parallelTasks by currentTaskItem.id. Returns the ManagedTaskState object whose .lifecycle field enables the Stop button during auto-approved tool execution when shoferAsk is undefined. |
| mcpAsyncCalls | Task.ts | Map of in-flight async MCP tool calls (call_mcp_tool_async), each with its own AbortController. Cleaned up by abortTask(). Cancellation is captured via captureMcpAsyncCallCancelled telemetry. |
| in-flight registry (mcp-server) | mcp.go | Go map map[string]map[string]context.CancelFunc keyed by (sessionId, requestId). Tracks cancellable in-progress requests so notifications/cancelled can abort upstream tools-backend HTTP calls. Entries are registered via registerInFlight and removed by deferred cleanup on completion. |
| webviewMessageHandler | webviewMessageHandler.ts | Central dispatch for all webview → host messages. Every WebviewMessage.type is handled here. |
| MessageQueueService | MessageQueueService.ts | Manages the per-task message queue. When a task is busy, user messages are enqueued; "Send Now" dequeues and sends immediately. |
| AskIgnoredError | AskIgnoredError.ts | Custom error thrown when a Task.ask() await is superseded or aborted. Used by cancelAndProcessQueuedMessages ("Send Now") and the ask() supersede logic to unwind the API loop cleanly without treating the event as a failure. |
| MessageManager | message-manager/index.ts | Manages adding/removing/editing messages within a task conversation. The single entry point for rewinding a timeline (edits/deletes/plugin restores). |
| ContextDropZoneProvider | ContextDropZoneProvider.ts | Native VS Code TreeView + TreeDragAndDropController for drag-and-drop context files into the chat. |
| addUrisToContext | ContextDropZoneProvider.ts | Exported async helper that converts file/folder URIs to workspace-relative paths, posts addContextFiles to the webview, sets a status-bar message, and focuses the sidebar. Shared between the native TreeView drop handler and the shofer.addFilesToContext Explorer context-menu command. |
| FileContextTracker | FileContextTracker.ts | Per-task file tracking for the agent's context: trackFileContext(relPath, source), the task metadata (files_in_context), the external-edit watchers, getFilesReadByRoo() / getFilesEditedByRoo(). Also the dispatch point for the beforeFileEdit / afterFileEdit plugin hooks (captureOriginal publishes the pre-edit content; it stores nothing). |
| ShoferIgnoreController | ShoferIgnoreController.ts | Defined but not yet imported/wired. Reads and enforces .shofer/shoferignore rules, filtering files from tool operations and context. |
| ShoferProtectedController | ShoferProtectedController.ts | Enforces write-protection via hardcoded PROTECTED_PATTERNS (.shofer/shoferignore, .shofer/shofermodes, .shoferrules*, .shofer/**, .vscode/**, *.code-workspace, .shoferprotected, AGENTS.md). Does NOT read a .shoferprotected file. |
| file-changes feature (basics plugin) | plugins/basics/src/file-changes/ | The bundled basics plugin's feature owning the File Changes panel: per-task base/ + final/ copies, the change list, revert/accept, and the get_changed_files tool. Fed by the beforeFileEdit / afterFileEdit hooks. No git dependency. |
| AutoApprovalHandler | AutoApprovalHandler.ts | Tracks consecutive API requests and cumulative cost (allowedMaxRequests, allowedMaxCost). Prompts the user when limits are exceeded, regardless of per-tool toggle state. Does NOT decide per-tool auto-approval — that lives in index.ts's checkAutoApproval. |
| CustomModesManager | CustomModesManager.ts | Reads .shofer/shofermodes files and manages custom mode definitions. |
| ProviderSettingsManager | ProviderSettingsManager.ts | Manages API provider configurations (API keys, endpoints, model selections). |
| ContextProxy | ContextProxy.ts | Provides a typed view of VS Code extension context for use across the extension. |
| McpHub | McpHub.ts | Central MCP (Model Context Protocol) hub. Manages MCP server connections, tool discovery, and resource access. |
| McpServerManager | McpServerManager.ts | Manages individual MCP server lifecycle (start, stop, restart). |
| DiffViewProvider | DiffViewProvider.ts | Opens VS Code diff editors for reviewing file changes. |
| TerminalRegistry | TerminalRegistry.ts | Manages terminal processes spawned by execute_command. |
| OutputInterceptor | OutputInterceptor.ts | Captures terminal output for display in chat. |
| ToolRepetitionDetector | ToolRepetitionDetector.ts | Detects consecutive identical tool calls (a common LLM loop pattern) and triggers corrective action. |
| NativeToolCallParser | NativeToolCallParser.ts | Parses tool call blocks from LLM streaming responses, mapping deprecated tool names to canonical forms. |
| getToolGroupForSayTool | tools.ts | Resolves a ShoferSayTool to its ToolGroup: native TOOL_GROUPS membership via the SAY_TOOL_TO_NATIVE_NAME mapping, then the custom-tool registry's declared group, then toolGroupRegistry.groupForTool, and only as a last resort prefix-based inference (browser* → the dynamic "browser" category, ide_* → "execute"). |
| SAY_TOOL_TO_NATIVE_NAME | tools.ts | Mapping from ShoferSayTool.tool (camelCase, e.g., "runSlashCommand") to canonical ToolName (snake_case, e.g., "run_slash_command"). Drives getToolGroupForSayTool. Missing entries silently fall through to uncategorized. |
| checkAutoApproval | index.ts | Main auto-approval decision function (async). Evaluates asks in fixed order: isAutoApprovableAsk → autoApprovalEnabled gate → followup → MCP → command → tool (with per-toggle checks). Returns { decision: "approve" | "deny" | "ask" | "timeout" }. |
| AutoApprovalState | group-gates.ts | Union type of the flat alwaysAllow* toggle keys — one per BUILTIN group: alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowMcp, alwaysAllowUncategorized, alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowExecute, alwaysAllowFollowupQuestions. A dynamic category has no flat key; it is gated by alwaysAllowGroups, which is an AutoApprovalStateOptions member. |
| alwaysAllowUncategorized | index.ts | Auto-approval toggle for MCP tools that declare no group (default to "uncategorized"). Only meaningful when alwaysAllowMcp is also true. |
| isAutoApprovableAsk | message.ts | Predicate returning true for asks that the host short-circuits without user input (command_output only today). These skip checkAutoApproval entirely via the fast-path at the top of index.ts. |
| unconditionally auto-approved tool | (concept) | A tool in checkAutoApproval that returns { decision: "approve" } before any alwaysAllow* toggle check: meta-operations (updateTodoList, skills, setTaskTitle, giveFeedback), background-task status tools (checkTaskStatus, listBackgroundTasks), async MCP status tools (checkMcpCallStatus, waitForMcpCall), lightweight read-only tools (findFiles, viewImage, getErrors, getChangedFiles, getProjectSetupInfo, readProjectStructure, listCodeUsages, lspSearch), and the mailbox tools (sendMessage, reply, wait). |
| filterPrivateToolsForMode | filter-tools-for-mode.ts | Filters extension-registered private LM tools (e.g., ide_*) based on the mode's allowed groups by reading each tool's group from the extension's toolGroups config. |
| BaseTool.handle() | BaseTool.ts | Wrapper method called from presentAssistantMessage.ts. Routes partial (streaming) tool calls to handlePartial(), then dispatches complete calls to execute(). Tools override execute() and optionally handlePartial() — they do NOT override handle(). |
| toolDescription() | presentAssistantMessage.ts | Inline function inside presentAssistantMessage() that maps block.name + block.params to a human-readable string for the ChatRow (e.g., "[write_to_file for 'src/app.ts']"). Every new tool MUST add a case in its switch. |
| TOOL_DISPLAY_NAMES | tool.ts | Record<ToolName, string> mapping every canonical tool name to its human-readable label (e.g., "execute_command" → "run commands"). Drives the tools-UI settings panel. Every new tool MUST add an entry here. |
| customTools | (field on ToolGroupConfig in tool.ts) | The write group has both tools (always available when write is permitted) and customTools (opt-in only, gated behind experiments.customTools). Adding a write-mutating tool to customTools instead of tools means it won't appear unless the user enables custom tools in Experiments. |
| Native Tool Checklist | adding-new-tools.md | The authoritative 11-step checklist for adding a new native tool. Follow this rather than copying examples from existing tools (which may predate current conventions). |
| WorktreeService | worktree-service.ts | The basics plugin's worktrees feature's wrapper around the git worktree CLI (list, create, delete, branches). Exported as singleton worktreeService. |
| WorktreeIncludeService | worktree-include.ts | The basics plugin's worktrees feature's service for .shofer/worktreeinclude file handling. Computes intersection of .shofer/worktreeinclude and .gitignore patterns, copies matching files via cp/robocopy. |
| working-directory backend | snapshot-store.ts | How the file-changes feature stores state: verbatim copies under <plugin storage>/tasks/<taskId>/base/<relPath> (the file before the task's first edit) and final/<relPath> (as the agent last left it), with hash-only metadata in originals/<sha1>.json and finals/<sha1>.json. No git dependency. Distinct from the checkpoints feature's shadow-git snapshots, which serve rollback, not file-change display. |
| worktree request surface | feature.ts | The basics plugin's worktrees methods (worktrees:list, worktrees:create, worktrees:delete, worktrees:branches, worktrees:defaults, worktrees:status, worktrees:select, and the un-namespaced resolve-task-cwd broadcast, …), reached from its UI over the plugin channel and from core's placement broadcast. Replaces the eleven webview worktree IPC messages. |
| SkillsManager | SkillsManager.ts | Discovers, caches, and manages skill definitions from .shofer/skills/. Exposes discoverSkills(), getSkillsMetadata(), getSkillsForMode(), getSkillContent(), and lifecycle methods (createSkill, deleteSkill, moveSkill). |
| LiveMemory | plugins/live-memory/ | Persistent agent that maintains long-term codebase context, answerable via the ask_live_memory tool. Now a bundled first-party plugin (disabled by default; requires billed-AI consent), not a built-in services/live-memory/ subsystem. |
| CodeIndexManager | manager.ts | Singleton-per-workspace orchestrator for RAG codebase indexing. Exposes initialize(), startIndexing(), stopIndexing(), searchIndex(), clearIndexData(), getCurrentStatus(). |
| CodeIndexConfigManager | config-manager.ts | Reads code-index settings from ContextProxy (global state + secrets). Detects config changes requiring restart. |
| CodeIndexStateManager | state-manager.ts | vscode.EventEmitter-based progress reporting: setSystemState(), recordFileIndexed(), setIndexedFileCount(). |
| CodeIndexOrchestrator | orchestrator.ts | Drives the indexing workflow: full scan → incremental scan → file watcher. Implements Phase 1 (mtime+size cache fast-path) and Phase 2 (git-aware narrowing). |
| CodeIndexServiceFactory | service-factory.ts | Creates IEmbedder, IVectorStore, DirectoryScanner, FileWatcher based on config. |
| CodeIndexSearchService | search-service.ts | Embeds query text → cosine similarity search against Qdrant. |
| DirectoryScanner | scanner.ts | Parallel file traversal with concurrency control. Batches code blocks, creates embeddings, upserts to Qdrant. Handles file deletions. |
| CodeParser | parser.ts | Uses web-tree-sitter for AST-aware parsing. Falls back to line-based chunking for unsupported languages. Also handles Markdown. |
| FileWatcher | file-watcher.ts | VS Code FileSystemWatcher for incremental re-indexing. Implements per-segment deduplication via segmentHash comparison. |
| CacheManager | cache-manager.ts | Persists per-file cache (v3: hash + mtimeMs + size + segmentHashes[]) to VS Code globalStorage. Drives Phase 1 fast-path. |
| QdrantVectorStore | qdrant-client.ts | Implements IVectorStore using @qdrant/js-client-rest. One collection per workspace. Stores metadata with git commit info. |
| GitIndexManager | git-index-manager.ts | Singleton-per-workspace service backing the git_search tool. Manages a separate Qdrant collection of embedded git commit messages (not diffs). Exposes searchIndex(), isFeatureEnabled, isFeatureConfigured. Requires git-index settings to be configured. |
| GitHistoryOrchestrator | git-history-orchestrator.ts | Drives the git indexing pipeline (extract → embed → upsert). Coordinates between GitLogExtractor, GitCacheManager, the embedder, the Qdrant store, and the GitWatcher. Owned by GitIndexManager. |
| GitHistoryStateManager | git-state-manager.ts | vscode.EventEmitter-based progress reporting for git indexing. States: Standby \| Indexing \| Indexed \| Error \| Stopping. Tracks indexedCommitCount and latestCommitHash. |
| GitCacheManager | git-cache-manager.ts | Per-commit SHA-256 content hash cache stored in VS Code globalStorage. Versioned snapshot (v2) with lastCommitDate field for incremental indexing. Skips unchanged commits on re-index. |
| GitLogExtractor | git-log-extractor.ts | Runs git log --format=... --encoding=UTF-8 with custom delimiters (\|\|\|, ENDCOMMIT) to produce structured GitCommitBlock[]. Truncates messages at 4000 chars before embedding. |
| GitWatcher | git-watcher.ts | Polls git log --since=<lastCommitDate> every N minutes (default 5) for incremental indexing. Emits onNewCommits event. Configurable branch via lazy getter. |
| GitSearchService | git-search-service.ts | Embeds queries and performs cosine similarity search against the git-specific Qdrant collection. Reuses the same IEmbedder and IVectorStore instances as the code index. |
| GitCommitBlock | git.ts | Interface: { commit_hash, short_hash, author, author_date, subject, body, content, contentHash }. The content field (subject + "\n\n" + body) is what gets embedded. |
| GitSearchResult | git.ts | Interface: { id, score, payload: { commit_hash, short_hash, author, author_date, subject, body } }. Returned by GitSearchService.search(). |
| GitSource | git-source.ts | Thin wrapper around VS Code built-in Git extension API. Provides diffSince(), discoverSubmodules(), diffSubmoduleSince(). |
| IEmbedder | embedder.ts | Interface: createEmbeddings(texts, model?), validateConfiguration(), embedderInfo. Implemented by 8 providers (openai, ollama, openai-compatible, gemini, mistral, vercel-ai-gateway, bedrock, openrouter). |
| IVectorStore | vector-store.ts | Interface: initialize(), upsertPoints(), search(), deletePointsByFilePath(), deletePointsByIds(), hasIndexedData(), markIndexingComplete/Incomplete(), clearCollection(), deleteCollection(), getMetadata(). |
| ICacheManager | cache.ts | Interface: deleteHash(filePath), flush(), getEntry(filePath), updateEntry(filePath, entry), getAllPaths(), getSegmentHashes(filePath). |
| ICodeParser | file-processor.ts | Interface: parseFile(filePath, options?) → CodeBlock[]. |
| IFileWatcher | file-processor.ts | Interface: initialize(), processFile(filePath), events: onDidStartBatchProcessing, onBatchProgressUpdate, onDidFinishBatchProcessing. |
| IndexingState | manager.ts | Union type: "Standby" | "Indexing" | "Indexed" | "Error" | "Stopping". Drives the state machine and the IndexingStatusBadge UI. |
| CodeBlock | file-processor.ts | Parsed code segment: { file_path, identifier, type, start_line, end_line, content, fileHash, segmentHash }. |
| segmentHash | (computed in parser.ts) | SHA-256(filePath + start_line + end_line + content.length + contentPreview[0:100]). Drives per-segment deduplication and Qdrant point IDs (uuidv5). |
| Per-segment deduplication | (in file-watcher.ts) | File watcher technique: compare new segmentHash set against cached segmentHashes[] to skip embedding reused blocks, embed only new/changed blocks, and delete stale Qdrant points. |
| Phase 1 (mtime+size fast-path) | (in manager.ts) | Startup cache check: stat() per file, compare mtimeMs+size against cache entry. Match → skip without reading or hashing. Mis-match → read + SHA-256. |
| Phase 2 (git-aware narrowing) | (in orchestrator.ts) | Startup git diff: if lastIndexedCommit exists in Qdrant metadata, diff only changed/deleted files plus dirty working tree. Bypasses directory walk entirely. |
| fallbackExtensions | supported-extensions.ts | Array of extensions (.vb, .swift, .elm) routed to line-based chunking instead of tree-sitter parsing. |
These components run in the React webview (iframe in VS Code).
| Canonical Name | File | Description |
|---|---|---|
| App | App.tsx |
Root component. Renders one of WelcomeView, HistoryView, SettingsView, or ChatView based on the active tab. |
| ExtensionStateContext | ExtensionStateContext.tsx |
React context that receives state pushes from the extension host and provides them to all child components. |
| useExtensionState | (hook from ExtensionStateContext) | React hook for accessing global ExtensionState. |
| vscode | vscode.ts |
Thin wrapper around acquireVsCodeApi() for posting WebviewMessages to the extension host. |
| telemetryClient | TelemetryClient.ts |
Client-side telemetry reporter using PostHog (feature-flagged). |
| useSelectedModel | useSelectedModel.ts |
Hook that resolves the current model's metadata (ID, context window, pricing) from the API configuration. |
| droppedContextFiles.ts | droppedContextFiles.ts |
Utility module for parsing drag-and-drop URI payloads. Exports DroppedContextFile type, extractUriPayload() (probes text/uri-list, text/plain, application/vnd.code.uri-list MIME types), and parseDroppedUris() (parses newline-separated URIs into workspace-relative DroppedContextFile[]). Used by ChatView handleWebviewDrop, ChatTextArea handleDrop, and the ChatTextArea test suite. |
Defined in packages/types/src/. Always refer to the canonical type name.
| Type | File | Description |
| -------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | --------- | --------------------------------------- | ----------- | ------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| activeTimeMs | history.ts | Accumulated active wall-clock time in milliseconds. Only counts time spent in the running lifecycle — excludes waiting_input, waiting, paused, idle, completed, and error states. Persisted per task for survival across restarts. Accumulated by TaskManager.setState() when leaving running. |
| HistoryItem | history.ts | Persisted task record. Contains id, ts, task (description), tokensIn, tokensOut, totalCost, taskState, activeTimeMs, parentTaskId, childIds, mode, cwd, pinned, archived, etc. |
| TaskState | history.ts | The full execution state: { lifecycle: TaskLifecycle, rating?: CompletionRating }. |
| TaskLifecycle | history.ts | Enum: "idle", "running", "waiting_input", "waiting", "paused", "completed", "error". |
| CompletionRating | history.ts | Agent self-assessment: "poor", "well", "excellent". Only set when lifecycle === "completed". |
| TaskNotification | history.ts | { taskId, type: "needs_input" | "completed" | "error" | "file_conflict", message, timestamp }. |
| CostLimit | history.ts | { maxUsd: number, action: BudgetAction } — per-root-task budget cap. Stored only on the root task (Task.costLimit); subtasks inherit via Task.resolveCostLimit(). Persisted through taskMetadata.ts. |
| BudgetAction | history.ts | Enum: "pause", "abort", "kill" — behavior when a CostLimit is exceeded. Defined by budgetActionSchema (Zod). |
| costLimitSchema | history.ts | Zod schema: z.object({ maxUsd: z.number().positive(), action: budgetActionSchema }). Defines the shape of HistoryItem.costLimit and defaultCostLimit setting. |
| budgetActionSchema | history.ts | Zod schema: z.enum(["pause", "abort", "kill"]). Describes the action taken when a cost limit is reached. |
| defaultCostLimit | global-settings.ts | Global setting (shape: costLimitSchema.nullish()) applied to new root tasks at creation time in ShoferProvider.createTask(). Wired in the schema but has no SettingsView UI row yet. |
| enableLlmProviderIntegration | global-settings.ts | Boolean setting (default false). When enabled, Shofer uses the shofer.llm.* VS Code commands from the llm-provider extension for USD pricing and cost-limit enforcement. |
| IDLE_TASK_STATE | history.ts | Exported constant: { lifecycle: "idle" }. Used as the default fallback in state resolution and as the target state when a task is stopped via TaskManager.stopManagedTask. |
| isTerminalLifecycle | history.ts | Function (lifecycle: TaskLifecycle) => boolean. Returns true for "completed", "error", and "paused" — lifecycles that survive a process restart. Used by sanitizeRestoredState to decide which states to preserve. |
| TaskHandle | task.ts | In-memory reference a parent Task holds for each background child: { taskId, status: BackgroundTaskStatus, createdAt, parentTaskId }. Intentionally minimal — no title or result caching. |
| BackgroundTaskStatus | task.ts | Union type: "starting" | "running" | "waiting" | "waiting_for_parent" | "completed" | "error" | "cancelled" | "paused". waiting_for_parentis set byAskFollowupQuestionToolwhile the child is parked on a question forwarded to its parent;check_task_status reads it. |
| Task.forwardedQuestion | Task.ts | Getter returning { envelopeId, question } \| undefined — the question this child forwarded to its parent, while it is still parked on it. Written by setForwardedQuestion, cleared by clearForwardedQuestion, and answered by answerForwardedQuestion(envelopeId, answer). Read by check_task_status. |
| Type | File | Description |
|---|---|---|
| ShoferMessage | message.ts |
A single message in a task conversation. Union of ShoferSay, ShoferAsk, and tool-related message types. |
| ShoferSay | message.ts |
A statement from the model (text, reasoning, tool call, etc.). Includes say type discriminant. |
| ShoferAsk | message.ts |
A question/approval request from the model (e.g., followup, tool, command, completion_result). |
| QueuedMessage | message.ts |
A user message waiting in the queue: { id, text, images?, timestamp }. |
| QueueEvents | MessageQueueService.ts |
Event map on MessageQueueService: { stateChanged: [messages: QueuedMessage[]] }. Fired after every addMessage / prependMessage / dequeueMessage / removeMessage / updateMessage so the webview re-renders QueuedMessages reactively. |
| MessageQueueState | MessageQueueService.ts |
State snapshot interface: { messages: QueuedMessage[], isProcessing: boolean, isPaused: boolean }. isProcessing and isPaused are declared for forward compatibility; only messages is currently maintained. |
| api_req_started | message.ts |
A ShoferSay message type (say: "api_req_started") emitted at the start of each API request. Carries per-call metadata (model, tokens, cost, errors, wire request) persisted in ui_messages.json. Used as the anchor for JSON task exports. |
| TodoItem | todo.ts |
{ id: string, content: string, status: TodoStatus }. |
| TodoStatus | todo.ts |
Enum: "pending", "in_progress", "completed" — the status of a todo item. |
| Type | File | Description |
| ------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| ToolName | tool.ts | Union of all canonical tool names (see §9). |
| ToolGroup | tool.ts | Tool category — BuiltinToolGroup \| (string & {}). The 8 builtins are "read", "write", "execute", "mcp", "mode", "subtasks", "questions", "uncategorized"; any other valid slug is a dynamic category (see §10). |
| ToolGroupConfig | tool.ts | { tools: readonly ToolName[], customTools?: readonly ToolName[] }. Note: there is no alwaysAvailable field on this type. |
| ALWAYS_AVAILABLE_TOOLS | tool.ts | Constant array of ToolName[] that bypass mode filtering entirely: attempt_completion, update_todo_list, run_slash_command, skills, set_task_title, give_feedback, list_background_tasks, send_message, reply, wait, describe_tools (the last additionally removed by computeToolAccess for a mode that declares no tools_full_schema). |
| SkillMetadata | skills.ts | Type for discovered skill metadata: { name, description, path, source: "global" | "project", mode?: string, modeSlugs?: string[] }. The modefield is deprecated in favor ofmodeSlugs. |
| SkillContent | skills.ts | Extends SkillMetadata with instructions: string — the full markdown body from SKILL.md, loaded on-demand. |
| SKILL.md format | (on-disk) | YAML frontmatter (name, description, optional modeSlugs) followed by markdown body. Names validated via validateSkillNameShared() from @shofer/types (regex /^[a-z0-9]+(-[a-z0-9]+)*$/, max 64 chars). |
| loadedSkills | Task.ts | Map<string, string> on each Task instance mapping skill name to absolute SKILL.md path. Cleared on context condense. Exposed to webview as Record<string, string> for SkillsButton popover. |
| TOOL_ALIASES | tool.ts | Maps deprecated tool names to canonical ones: write_file → write_to_file, search_and_replace → edit. |
| ToolUsage | tool.ts | Per-tool usage counters: { [toolName: ToolName]: { attempts: number, failures: number } }. Serialized with toolUsageSchema for persistence. |
| ModelInfo.excludedTools | tool.ts | string[] — tool names (canonical or aliased) to remove from the allowed set for a specific model. Applied in applyModelToolCustomization(). |
| ModelInfo.includedTools | tool.ts | string[] — tool names (canonical or aliased) to add to the allowed set, gated by mode group membership. Applied in applyModelToolCustomization(). Alias names (e.g., "search_and_replace") are resolved to canonical form and tracked in aliasRenames. |
| applyModelToolCustomization | filter-tools-for-mode.ts | Function at filter-tools-for-mode.ts:154 that applies excludedTools (removals) and includedTools (additions with group check) from ModelInfo to an allowed-tool set. Returns { allowedTools, aliasRenames }. |
| resolveToolAlias | filter-tools-for-mode.ts | Function at filter-tools-for-mode.ts:98 that maps alias names to canonical tool names using the ALIAS_TO_CANONICAL reverse map (built from TOOL_ALIASES). Used by applyModelToolCustomization, validateToolUse, and NativeToolCallParser. |
| applyRouterToolPreferences | router-tool-preferences.ts | Function at router-tool-preferences.ts:16 that applies tool preferences per model family for dynamic router providers (OpenRouter, Requesty). Currently only targets "openai"-containing model IDs (adds apply_patch, removes apply_diff/write_to_file). |
| DroppedContextFile | droppedContextFiles.ts | Webview-local type: { path: string, isFile: boolean }. Carries a workspace-relative file path and a best-effort isFile flag. Produced by parseDroppedUris() and consumed by ChatView's droppedContextFiles state, onContextFilesDropped callback, and the addContextFiles IPC message payload. Not in @shofer/types — it is a webview utility type. |
| onContextFilesDropped | (callback prop on ChatTextArea) | (files: DroppedContextFile[]) => void — passed from ChatView to ChatTextArea to feed path-style drops (Explorer files, editor tabs) into droppedContextFiles state. The primary working webview-side drop path on VSCode Desktop. |
| model_preferences.md | docs/ | Documentation file recording tool inclusion/exclusion and alias preferences across providers. See docs/model_preferences.md. |
Defined in mcp.ts, tool.ts, and McpHub.ts.
| Type | File | Description |
|---|---|---|
| McpServer | mcp.ts |
Connected MCP server state: { name, config, status, error?, tools?, resources?, resourceTemplates? }. |
| McpTool | mcp.ts |
An MCP tool discovered from a server: { name, description?, inputSchema, enabledForPrompt?, group? }. |
| McpResource | mcp.ts |
An MCP resource: { uri, name, description?, mimeType? }. |
| McpToolUse | tool.ts |
Discriminated block type (type: "mcp_tool_use") for native mcp-- prefixed tool calls. Carries serverName, toolName, arguments, id. |
| McpExecutionStatus | mcp.ts |
Webview streaming status: { executionId, status: "started" | "output" | "completed" | "error", serverName, toolName, response?, error? }. |
| McpServerUse | mcp.ts |
Parsed approval payload for use_mcp_server asks: { type: "use_mcp_tool" | "access_mcp_resource", serverName?, toolName?, ... }. |
| McpToolCallResponse | mcp.ts |
Raw response from McpHub.callTool(): { content: McpContent[], isError?: boolean }. |
| ServerConfigSchema | McpHub.ts (Zod) |
Zod schema validating each MCP server entry. Exported from McpHub.ts (line 148). Defines type, command, args, url, headers, timeout, disabledTools, toolGroups. |
mcp-- prefix |
(convention) | Naming convention for native MCP tools: mcp--{serverName}--{toolName}. Built by buildMcpToolName(), parsed by parseMcpToolName(). Capped at 64 chars for Gemini. |
| use-mcp-shared.ts | mcp/ |
Shared MCP helpers module at use-mcp-shared.ts. Exports validateMcpToolExists(), processMcpToolContent(), runMcpToolCall(), and sendExecutionStatus(). Used by both use_mcp_tool and call_mcp_tool_async. |
| taskId | task.taskId |
The task id (UUID v7) — the single correlation id across the platform. Passed from the Shofer extension host to mcp-server via MCP _meta["shofer.dev/taskId"], forwarded as task_id to tools-backend, and sent as task_id to llm-router, for logging, metrics, and distributed tracing. See docs/taskId.md. |
_meta |
(MCP protocol) | The MCP protocol's standard metadata field in tools/call request params. Shofer injects _meta["shofer.dev/taskId"] and _meta["shofer.dev/toolCallId"] here to avoid argument pollution and maintain compatibility with third-party MCP servers that use additionalProperties: false. |
shofer.dev/ prefix |
McpHub.ts |
The MCP _meta key prefix Shofer writes under (MCP_META_PREFIX), from the project's own domain. MCP makes a key <prefix>/<name> where a prefix is dotted labels followed by a slash — a dotted string without one is a bare name, namespaced in spelling only. Replaced the unprefixed vscode.taskId / shofer.toolCallId. See docs/taskId.md. |
shofer.dev/taskId |
(MCP _meta key) |
Carries task.taskId on every tools/call. Required by mcp-server, which refuses a call without it. |
shofer.dev/toolCallId |
(MCP _meta key) |
Carries the provider's own tool_calls[].id for the call, raw. Optional — omitted when the invocation did not come from a native provider tool call. |
task_id |
mcp-server / tools-backend |
The JSON body field used when forwarding the taskId from mcp-server to tools-backend via backend.go. Maps the MCP-protocol-level _meta["shofer.dev/taskId"] to the tools-backend REST API convention of snake_case. |
runMcpToolCall |
mcp/ |
Async function in use-mcp-shared.ts that runs an MCP tool call through McpHub.callTool(). Threads task.taskId as the taskId parameter and emits execution status to the webview. Used by both UseMcpToolTool (sync) and CallMcpToolAsyncTool (async). |
mcp_server_request_started |
message.ts |
ShoferSay type (say: "mcp_server_request_started") emitted at the start of every MCP tool call. |
mcp_server_response |
message.ts |
ShoferSay type (say: "mcp_server_response") emitted with the MCP tool call result text and images. |
Defined in types.ts — the plugin's own wire
types, shared between its extension half and its UI bundles. Core has no worktree types.
| Type | Description |
|---|---|
| Worktree | { path, branch, commitHash, isCurrent, isBare, isDetached, isLocked, lockReason? } |
| WorktreeResult | { success, message, worktree? } — operation result. |
| CreateWorktreeOptions | { path, branch?, baseBranch?, createNewBranch? } — creation parameters. |
| BranchInfo | { localBranches[], remoteBranches[], currentBranch } — return of getAvailableBranches. |
| WorktreeIncludeStatus | { exists, hasGitignore, gitignoreContent? } — .shofer/worktreeinclude file status. |
| WorktreeListResponse | { worktrees[], isGitRepo, isMultiRoot, isSubfolder, gitRootPath, error? } — the list reply. |
| WorktreeDefaultsResponse | { suggestedBranch, suggestedPath, error? } — auto-generated defaults for new worktrees. |
| WorktreeStatus | { branch, path, baseBranch, commitsAhead, commitsBehind, filesChanged, insertions, deletions, hasUncommittedChanges, uncommittedCount, lastCommit, mergeReadiness, isBaseBranch, otherWorktrees[] } — detailed worktree status. |
| CopyProgress | { bytesCopied, itemName } — progress callback payload for .shofer/worktreeinclude copy. |
| CopyProgressCallback | (progress: CopyProgress) => void — callback type for .shofer/worktreeinclude copy progress reporting. |
| Type | File | Description |
|---|---|---|
| ExtensionState | vscode-extension-host.ts |
Full state object sent from extension host to webview. Contains shoferMessages, taskHistory, apiConfiguration, mode, parallelTasks, taskNotifications, etc. |
| ProviderSettings | provider-settings.ts |
API provider configuration: apiProvider, apiModelId, apiKey, baseUrl, etc. |
| ModeConfig | mode.ts |
Custom mode definition: slug, name, roleDefinition, tools, customInstructions, tools_allowed, tools_denied. |
| WebviewMessage | vscode-extension-host.ts |
Union of all messages sent from webview → extension host. Every message has a type discriminant. |
| ExtensionMessage | vscode-extension-host.ts |
Union of all messages sent from extension host → webview. |
| ManagedTask | vscode-extension-host.ts |
(via TaskManager) Runtime task descriptor: { id, name, taskId, workspace, createdAt, lastActiveAt, state, activeTimeMs }. activeTimeMs accumulates wall-clock time in the running lifecycle only. |
| JsonExportTrace | export-json.ts |
Top-level JSON export schema. Contains version, taskId, task, mode, createdAt, calls[], totalTokens, totalCostUsd, totalCalls, totalToolCalls. |
| JsonExportCall | export-json.ts |
A single API call entry in a JSON export trace. Contains index, apiProtocol, model, token counts, costUsd, messages[], toolCalls[], reasoning, retryAttempt, error, wireRequest, and _tokensEstimated. |
| JsonExportToolCall | export-json.ts |
A tool call within a JsonExportCall. Contains name, id, input, and optional result ({ content, isError }). |
| ChangedFileEntry | plugins/basics/src/file-changes/types.ts |
{ path, insertions, deletions, binary, state: "modified" | "added" | "deleted", hasOriginalContent, hasFinalContent }. The file-changes feature's own shape, shared only between its extension half and its panel. |
| ChangedFilesPayload | plugins/basics/src/file-changes/types.ts |
{ taskId, entries: ChangedFileEntry[] }. What the plugin's file-changes:get request returns and its panel push carries. |
| FileSnapshot | plugins/basics/src/file-changes/snapshot-store.ts |
{ kind: "absent" | "text" | "binary", hash?: string }. Per-task per-file metadata in originals/<sha1>.json / finals/<sha1>.json. No inline content — the bytes live in base/<relPath> and final/<relPath>. |
| SnapshotKind | plugins/basics/src/file-changes/snapshot-store.ts |
Union type: "absent" (the file did not exist at capture time), "text" (it existed, content in base/ or final/), "binary" (declared for consumers; nothing produces it yet). |
Files stored under {globalStorageUri}/tasks/{taskId}/ for each task. These are the sources for JSON and Markdown task exports.
| File | Writer | Contents |
|---|---|---|
history_item.json |
TaskHistoryStore |
HistoryItem — task metadata (id, task, mode, ts, tokens, cost, size). |
api_conversation_history.json |
Task.addToApiConversationHistory() |
Anthropic.MessageParam[] — full LLM conversation with tool_use, tool_result, reasoning, and thinking blocks. |
ui_messages.json |
Task.saveShoferMessages() |
ShoferMessage[] — UI-level messages including api_req_started entries that carry per-call metadata (tokens, cost, errors, wire request). |
| Term | Description |
|---|---|
| Token estimation | Char/4 fallback heuristic triggered when all API calls in a trace have zero tokens from provider usage chunks. Estimated calls are marked _tokensEstimated: true. |
| Error-only call | An API call that never received an assistant response (connection failure, rate limit, empty stream). Export produces a JsonExportCall with messages: [] and toolCalls: [] but carries error and wire metadata. |
| Call partitioning | The process in buildJsonTrace() that splits apiConversationHistory into per-request JsonExportCall entries by walking assistant message boundaries and matching with api_req_started entries. |
Communication between the webview (React) and extension host (Node.js) uses typed discriminated unions.
The extension host posts messages via ShoferProvider.postMessageToWebview(). Key types:
type |
Purpose |
|---|---|
"state" |
Full or partial ExtensionState push. |
"action" |
Actions like tab switches, input focus, auto-approve toggles. newMenuButtonClicked and launcherButtonClicked both open LauncherView. |
"taskHistoryUpdated" |
The task history list changed. |
"parallelTasksUpdated" |
The parallel task runtime state changed. |
"taskNotification" |
A background task needs attention. |
"condenseTaskContextStarted" |
Context condensation has begun (triggered when context window is near capacity). |
"indexingStatusUpdate" |
Code index status changed. |
"liveMemoryStatusUpdate" |
Live Memory status changed. |
"addContextFiles" |
Files were dropped onto the drop zone; webview should add them as context tags. |
"mcpServers" |
MCP server list changed (new server connected, disconnected, tools updated). Carries full McpServer[] array. |
"mcpExecutionStatus" |
Real-time MCP tool execution status update. Carries McpExecutionStatus as JSON string in text. |
The webview posts messages via vscode.postMessage(). Key types:
type |
Purpose |
|---|---|
"newTask" |
User sent a message (starts a new task). Carries text, images, and mode. |
"launchTask" |
User picked a mode card in LauncherView. Backgrounds the current task and starts a fresh task in mode (defaults to defaultModeSlug). |
"cancelTask" |
User clicked Stop. |
"focusParallelTask" |
User switched to a different task via TaskSelector. |
"createParallelTask" |
User created a new parallel task (via task sidebar drawer). |
"queueMessage" |
User typed a message while the task is busy; enqueue instead of sending. |
"cancelAndSendQueuedMessages" |
User clicked Send Now to cancel the current turn and send the queued message immediately. |
"deleteMessageConfirm" |
User confirmed deletion of a message. |
"editMessageConfirm" |
User confirmed editing of a message. |
"webviewDidLaunch" |
Webview initialized and ready to receive state. |
"openImage" |
Open an image in VS Code's built-in image viewer (sent from Thumbnails, ImageViewer). |
"selectImages" |
Request OS file picker for image selection (sent from ChatTextArea image button). |
"openMention" |
Request file listing for @mention autocomplete. |
Defined in tool.ts as the toolNames const. Always use these exact strings when referring to a tool:
read_file— Read file contents with offset/limit or indentation-based extraction.write_to_file— Write complete file content (creates directories automatically).apply_diff— Apply targeted modifications via search/replace blocks.edit/edit_file/search_and_replace/search_replace/apply_patch— Legacy/compatibility edit tool aliases.insert_edit— Insert text at a specific line/column position.sed— Regex find-and-replace on files.file— Filesystem operations viarm/mvsubcommands.
rag_search— Semantic search using the vector index (RAG).lsp_search— Symbol search via LSP workspace symbols (fallback to text search).grep_search— Regex/literal search across files with context display.list_files— List directory contents (optional recursive).find_files— Find files by glob pattern.list_code_usages— Find all references to a symbol via LSP.read_project_structure— Tree view of workspace directory structure.get_errors— Get diagnostics from language servers.get_project_setup_info— Analyze project for languages, frameworks, build systems.git_search— Search git commit history (commit messages only) using semantic search.
execute_command— Run CLI commands with configurable cwd and timeout.read_command_output— Retrieve full output from a truncated command execution.
attempt_completion— Signal task completion with self-assessment rating.new_task— Spawn a concurrent child task.check_task_status— Query the status of a child or peer task.send_message— Put an envelope in another task's mailbox.reply— Answer a request sitting in this task's mailbox.wait— Read this task's mailbox, parking until mail arrives.list_background_tasks— List all background child tasks.switch_mode— Switch to a different mode.set_task_title— Set a descriptive title for the current task.ask_followup_question— Ask the user a multiple-choice question.ask_live_memory— Query the persistent live memory.give_feedback— Send feedback to the Shofer.Dev developers.cancel_tasks— Stop one or more background child tasks.describe_tools— Return the full parameter schemas of tools a mode declared as stubs (tools_full_schema).
fetch_web_page— Download and extract text from web pages.view_image— View an image file.generate_image— Generate an image via AI.
create_directory— Create a new directory.create_new_workspace— Create a new workspace/project structure.rename_symbol— Rename a symbol and all its references via LSP.skills— Load a skill by name.update_todo_list— Replace the TODO list.run_slash_command— Execute a slash command.
The following commands are available via run_slash_command and ship in the bundled basics plugin's worktrees feature (plugins/basics/commands/). Because the plugin is first-party and sets unqualifiedContributions, they keep their bare names at the built-in precedence tier — so a project-level .shofer/commands/ file of the same name still takes precedence.
merge-worktree— Merge a worktree branch into base with a merge commit (no cleanup).merge-worktree-cleanup— Merge a worktree branch into base, then delete the branch and worktree directory.rebase-worktree— Rebase a worktree branch onto base, fast-forward merge (no cleanup).rebase-worktree-cleanup— Rebase + fast-forward, then delete the branch and worktree directory.dryrun-rebase-worktree— Preview rebase conflicts without committing changes.worktree-status— Detailed status report for a worktree branch.
use_mcp_tool— Invoke a tool from an MCP server.access_mcp_resource— Access a resource from an MCP server.call_mcp_tool_async— Call an MCP server tool asynchronously (fire-and-forget).check_mcp_call_status— Check the status of an async MCP tool call.wait_for_mcp_call— Block until async MCP tool calls complete.
Mapping from old names to canonical names (auto-translated by NativeToolCallParser and TOOL_ALIASES):
| Old Name | Canonical Name |
|---|---|
skill_load |
skills |
write_file |
write_to_file |
search_and_replace |
edit |
list_code_definition_names |
(removed — PR #10005) |
Every tool belongs to exactly one tool group. Tool groups are used for mode
access control and auto-approval toggles. The vocabulary is open over a closed
set of 8 builtins: toolGroups in
tool.ts is the reserved BuiltinToolGroup
union, and ToolGroup = BuiltinToolGroup | (string & {}) is the open type every
declaration site accepts.
| Builtin group | Description |
|---|---|
| read | Read-only data access (files, search, diagnostics). |
| write | Content mutations (apply_diff, write_to_file, etc.). |
| execute | System command execution (execute_command, read_command_output). |
| mcp | MCP protocol tools (use_mcp_tool, access_mcp_resource). |
| mode | Mode switching tools (switch_mode). |
| subtasks | Background/delegated task management tools. |
| questions | User-facing question tools (ask_followup_question). |
| uncategorized | Fallback for tools that declare nothing usable. |
Any other valid slug (toolGroupNameSchema: /^[a-z0-9]+(-[a-z0-9]+)*$/, ≤64
chars) is a dynamic category — minted at registration by whatever declared
it (an MCP server's _meta, an mcp.json toolGroups entry, a private-tool
provider, a plugin's custom tool, the MCP group dropdown), recorded in
toolGroupRegistry
(category-registry.ts),
and gated by its entry in the alwaysAllowGroups record rather than by a flat
alwaysAllow* key. browser is one: it carries no native tools and has no
builtin toggle. "*" is the reserved wildcard and is not a valid category name.
See tool-categories.md.
| Old Name | Canonical Name |
|---|---|
edit |
write |
command |
execute |
modes |
mode |
Built-in modes, contributed by the bundled builtin-config plugin
(plugins/builtin-config/plugin.json, see
plugins/builtin-config/docs/modes.md):
| Slug | Display Name | Description |
|---|---|---|
code |
💻 Code | Default mode. Write, modify, refactor code. |
architect |
🏗️ Architect | Plan, design, strategize before implementation. |
debug |
🪲 Debug | Troubleshooting, diagnostics, root cause analysis. |
code-search |
🔎 Code Search | Search the codebase for specific information. |
web-search |
🌐 Web Search | Web browsing, research, data extraction. |
reviewer |
👀 Reviewer | Code review without making changes. |
Custom modes can be defined via .shofer/shofermodes files.
Custom Mode Fields: slug, name, roleDefinition, tools (tool groups), tools_allowed, tools_denied, customInstructions, whenToUse, description, source ("project" | "global"), provider.
See also task_states.md.
The icon for a task (in TaskSelector and TaskHeader) is resolved as:
runtime.state— live execution state fromManagedTask(in-memory), always wins if present.item.taskState— persisted state fromHistoryItem(survives restarts).{ lifecycle: "idle" }— default fallback.
| State | Color | Class | Effect |
|---|---|---|---|
| idle | Gray | bg-gray-400 |
– |
| running | Green | bg-green-500 |
Pulse |
| waiting_input | Yellow | bg-yellow-500 |
Pulse |
| waiting | Blue | bg-blue-500 |
Pulse |
| paused | Orange | bg-orange-500 |
– |
| completed | Green | bg-green-500 |
– |
| error | Red | bg-red-500 |
– |
waitingvswaiting_input:waiting_inputmeans the task is paused waiting for user approval or input (e.g., tool-approval prompt,ask_followup_question).waitingmeans the task is blocked on a non-user external event — parked inwaiton its mailbox, or on an async MCP call viawait_for_mcp_call. Onlywaiting_inputtriggers a notification badge in the TaskSelector.
The visual display for each state (icon + color) is produced by these entities in TaskSelector.tsx:
| Entity | File | Description |
|---|---|---|
| LifecycleVisual | TaskSelector.tsx |
Type defining the visual config shape: { dot, label, pulse, icon, iconColor }. |
| LIFECYCLE_VISUAL | TaskSelector.tsx |
Record<TaskLifecycle, LifecycleVisual> — maps each lifecycle phase to its codicon + color. Exported. |
| RATING_VISUAL | TaskSelector.tsx |
Record<CompletionRating, ...> — overlay visuals for completed tasks. Not exported (private to the module). |
| resolveStateVisual | TaskSelector.tsx |
(state?: TaskState) => LifecycleVisual — resolves the visual by combining LIFECYCLE_VISUAL[lifecycle] with RATING_VISUAL[rating] when lifecycle is "completed". Exported. |
The dot field in LIFECYCLE_VISUAL uses VSCode CSS custom properties (paired with Tailwind arbitrary-value syntax bg-[var(--vscode-...,fallback)]). These are the canonical color variables:
| CSS Variable | Used For | Fallback |
|---|---|---|
--vscode-descriptionForeground |
idle, completed·poor | (none) |
--vscode-charts-green |
running, completed·well, completed·excellent | #16a34a |
--vscode-charts-yellow |
waiting_input | #eab308 |
--vscode-charts-blue |
waiting | #3b82f6 |
--vscode-charts-orange |
paused | #f97316 |
--vscode-errorForeground |
error | #ef4444 |
Do NOT use Tailwind utility classes (bg-gray-400, bg-green-500, etc.) to document state-dot colors — these are not the rendering mechanism. The colors are resolved at runtime by VS Code's theme engine.
| Entity | File | Description |
|---|---|---|
| sanitizeRestoredState | TaskManager.ts |
Static method that downgrades transient lifecycles (running, waiting_input, waiting) to idle when rehydrating tasks after a process restart. Terminal lifecycles (completed, error, paused) are preserved. |
| Event | When |
|---|---|
TaskStarted |
First API call begins. |
TaskInteractive |
Needs user input (approval/question). |
TaskActive |
Resumed after user input. |
TaskIdle |
Reached idle state (completion, error, cancel). |
TaskCompleted |
Finished with token/tool usage summary. |
TaskPaused |
Manually paused by user. |
TaskResumed |
Resumed from pause. |
When a task reaches its CostLimit.maxUsd:
| Action | Behavior |
|---|---|
pause |
Pause the task, ask user to increase limit. |
abort |
Abort the task without completion. |
kill |
Kill the task immediately. |
| File / Directory | Purpose |
|---|---|
.shofer/shoferignore |
Gitignore-style file listing paths Shofer should not access (index, read, search). |
.shofer/shofermodes |
YAML file defining project-level custom mode overrides. Takes highest priority in the mode merge chain. |
custom_modes.yaml |
Runtime artifact at <globalStorage>/settings/custom_modes.yaml storing per-user mode customizations. NOT part of the Shofer source tree. |
mcp_settings.json |
Global MCP server definitions at <globalStorage>/settings/mcp_settings.json. Managed by McpHub. |
.shofer/mcp.json |
Per-project MCP server definitions at <workspace>/.shofer/mcp.json. Watched by McpHub.watchProjectMcpFile(). |
shofer-code-settings.json |
Full-settings export file containing providerProfiles + globalSettings. Created by exportSettings() in importExport.ts. |
.shoferprotected |
File defining protected files/directories that require explicit approval to modify. |
.shofer/rules/ |
Additional rules/prompts loaded into the system prompt. |
.shofer/skills/ |
Skill definitions (SKILL.md files) for domain-specific instructions. |
SKILL.md |
A single skill definition file containing instructions, mode restrictions, and optional linked files. |
AGENTS.md |
Developer-facing documentation about the extension's architecture and conventions. |
.shofer/worktreeinclude |
Custom .gitignore-syntax file listing files/directories to copy from source worktree to newly created ones. Only copies files that match BOTH .shofer/worktreeinclude and .gitignore. |
.worktrees/ |
Convention directory for embedded git worktrees. Each worktree lives at <workspace>/.worktrees/<name>/ (EMBEDDED_WORKTREES_DIR). Enforced by the basics plugin's worktrees feature's enforceConventions() path normalization. |
<globalStorage>/plugins/basics/file-changes/tasks/<taskId>/ |
The file-changes feature's per-task copies: base/ (the file before the task's first edit), final/ (as the agent last left it), and the hash-only metadata in originals/ / finals/, keyed by SHA-1 of the relative path. |
shofer-original: |
Virtual document URI scheme registered in extension.ts for click-to-diff in the FileChangesPanel. The original content is base64-encoded in the URI query — no on-disk files are created. Resolved by an anonymous TextDocumentContentProvider. |
The tool preparation progress indicator replaces the old thinking-bubble
noise with an inline chat row showing a spinner, tool name, and byte count.
See tool-preparing-progress.md for the full design.
| Term | Description |
|---|---|
| tool_preparing | A ShoferSay type (partial: true) emitted per tool-call argument accumulation update. Renders as an inline row with spinner and byte count. |
| tool_preparing marker | Null-byte-delimited protocol message: \x00tool_preparing\x00<toolName>\x00<byteCount>\x00. Emitted by llm-provider, detected via regex in vscode-lm.ts. |
| ApiStreamToolPreparingChunk | Stream chunk type in stream.ts carrying { type: "tool_preparing", toolName, byteCount }. |
| buildPreparingMarker | Function in language-model-provider.ts constructing the null-delimited marker string. |
| dismissToolPreparingRow | Method on Task that sets partial: false on any outstanding tool_preparing row when a tool call reaches a terminal state. |
| lastVisibleEmitMs | Timestamp in llm-provider tracking the last host-visible emission. Assigned but not yet read — reserved for a future timer-based heartbeat. |
| supportsImages | Boolean flag on model metadata indicating vision/support. Set per-model by provider fetchers (e.g., vercel-ai-gateway.ts). For vscode-lm, sourced dynamically from the shofer.llm.getModelCapabilities side-channel command. Propagated to the webview as shouldDisableImages. |
| maybeRemoveImageBlocks | Function in image-cleaning.ts that replaces image content blocks with [Referenced image in conversation] placeholder text when the model lacks vision support. Prevents API errors while preserving conversational context. |
| maxImageFileSize | Setting (default 5 MB) controlling maximum size of individual image files processed by read_file. Defined in global-settings.ts. |
| maxTotalImageSize | Setting (default 20 MB) controlling maximum total size of all images in a single read_file operation. Defined in global-settings.ts. |
| Term | Description |
|---|---|
| Provider Profile | A named API configuration (e.g., "openrouter", "deepseek") stored in VS Code settings. Selected via ApiConfigSelector. |
| Sticky Profile | Each task remembers its apiConfigName; switching tasks restores that task's provider profile. |
| Sticky Mode | Each task remembers its mode; switching tasks restores that task's mode. |
| Lock API Config | Feature that prevents the model from switching API profiles. |
| Provider Name | The canonical provider identifier: "openrouter", "anthropic", "openai", "deepseek", "gemini", "vscode-lm", "ollama", etc. |
| Router Provider | The Shofer Router API ("router-provider") which proxies to upstream providers (OpenRouter, Anthropic, OpenAI, etc.). |
| Context Window | The maximum number of tokens a model can process in a single request. Displayed in ContextWindowProgress. |
| Consecutive Mistake Limit | Maximum number of consecutive errors (no tools used, tool repetition) before the task is auto-aborted. |
| Prompt Enhancement | The ✨ button that sends the user's draft to a separate LLM call for improvement before sending to the main model. |
| apiProtocol | Discriminator set on each JSON export call indicating the wire protocol: "anthropic" or "openai". Set via getApiProtocol(). Never "openai-native" at runtime. |
| getApiProtocol() | Pure function in provider-settings.ts that resolves a provider+model to its wire protocol. Returns "anthropic" for Anthropic-style providers (anthropic, bedrock, vertex+claude models), "openai" for everything else. |
| SecretStorage | VS Code's OS-level credential API (libsecret/Keychain/Credential Manager). Stores API profiles blob and individual API keys. Falls back to in-memory store in containers. |
| globalState | VS Code extension state API backed by SQLite at <userData>/globalStorage/<publisher>/state.vscdb. Stores non-secret settings (mode, auto-approval toggles, custom instructions). Managed via ContextProxy. |
| SCOPE_PREFIX | ProviderSettingsManager.SCOPE_PREFIX = "shofer_config_" — the prefix prepended to SecretStorage keys to namespace them. Composes with "api_config" to produce "shofer_config_api_config". |
| shofer_config_api_config | The constructed SecretStorage key (\${SCOPE_PREFIX}api_config`) holding the ProviderProfiles` JSON blob (all API configurations, mode assignments, cloud profile IDs, migrations). |
| globalSettingsExportSchema | Zod schema in ContextProxy.ts — globalSettingsSchema minus taskHistory, listApiConfigMeta, and currentApiConfigName. Drives full-settings export. |
These terms describe the pipeline that delivers model context window sizes from the Go backend to the React UI. See contextlength.md for the full pipeline.
| Term | Description |
|---|---|
| ContextLength | Go struct field on ModelRegistry — the single source of truth for per-model context window sizes. Defined as ContextLength int. |
| context_length | JSON field in the llm-router /v1/models API response, set from m.ContextLength at models.go:226. |
| contextWindow | TypeScript field on ModelInfo in @shofer/types. Set by provider-specific hooks and handlers from the upstream context_length or maxInputTokens value. Displayed in the context window progress bar. |
| maxInputTokens | VSCode LM API property on LanguageModelChatInformation — the VSCode-level carrier for context window size. Populated by llm-provider from contextLength ?? 4096 at language-model-provider.ts:976. |
| openAiModelInfoSaneDefaults | Exported constant in openai.ts with contextWindow: 128_000. Used as fallback when model metadata is unavailable. Previously caused the 128K bug where the webview fell through to this default for unknown vscode-lm models. |
| vsCodeLmModels | Dynamic state array (VsCodeLmChatInfo[]) in ExtensionStateContext.tsx. Populated by the requestVsCodeLmModels IPC handler, replacing the old static map. |
| VsCodeLmChatInfo | Interface in vscode-llm.ts carrying maxInputTokens, shoferCapabilities, and shoferPricing from the extension host to the webview. Enriches VS Code's native LanguageModelChatInformation with side-channel data. |
| shoferCapabilities | Field on VsCodeLmChatInfo (interface shoferLmCapabilities) carrying imageInput, toolCalling, and promptCache. Sourced from llm-router via the shofer.llm.getModelCapabilities side-channel command in llm-provider. |
| shoferPricing | Field on VsCodeLmChatInfo (interface shoferLmPricing) carrying inputPrice, outputPrice, cacheReadsPrice?, cacheWritesPrice?. Sourced from llm-router via the shofer.llm.getModelPricing side-channel command. |
| requestVsCodeLmModels | IPC message type sent from the webview (WebviewMessage) to request fresh VsCodeLmChatInfo[] data. Handled at webviewMessageHandler.ts:1238. |
| shofer.llm.getModelCapabilities | Side-channel VS Code command registered by llm-provider that returns full model capabilities (including promptCache) from llm-router's registry. VS Code's native LanguageModelChatProviderCapabilities lacks a promptCache slot. |
| shofer.llm.getModelPricing | Side-channel VS Code command registered by llm-provider that returns per-token pricing (USD per 1M tokens) from llm-router. VS Code's native API has no pricing mechanism. |
Context management keeps AI conversations within the model's context window limit. See summarization.md for the full design.
| Term | Description |
|---|---|
| Context Condensation | LLM-based summarization of older conversation messages into a compact summary. Triggered when token usage reaches a configurable percentage of the context window. Preserves <command> blocks and file structure across condensings. |
| Context Management | The combined system of condensation + sliding window truncation. Orchestrated by manageContext(). |
| Condense Module | The packages/core/src/condense/ module that handles LLM-based conversation summarization, message transformation, and orphan tool-result injection. |
| Sliding Window Truncation | Non-destructive fallback when condensation fails. Tags oldest visible messages with truncationParent (hides them from the API) instead of deleting them. Controlled by truncateConversation(). |
| Fresh Start Model | Post-condensation strategy where the summary is inserted as a role: "user" message and ALL prior messages are tagged with condenseParent. The model sees only the summary (not the full history) on the next API call — a true fresh start. |
| Profile-Level Thresholds | Per-API-profile override of the global autoCondenseContextPercent (default 90). Stored as Record<string, number> in profileThresholds on ContextManagementOptions. A value of -1 means "inherit from global." |
TOKEN_BUFFER_PERCENTAGE |
Hardcoded constant (0.1 = 10%) in context-management/index.ts that acts as an absolute safety net — condensation/truncation always fires by ~90% utilization regardless of the user-configured percentage threshold. |
condenseParent |
Field on ApiMessage that points to the condenseId of the summary message that replaces this message. Messages with a condenseParent pointing to an existing summary are filtered out by getEffectiveApiHistory(). |
truncationParent |
Field on ApiMessage that points to the truncationId of the truncation marker that hides this message. Messages with a truncationParent pointing to an existing truncation marker are filtered out by getEffectiveApiHistory(). |
| Folded File Context | Signatures-only file definitions generated via generateFoldedFileContext() using tree-sitter. Each read file gets its own <system-reminder> block in the condensed summary, preserving structural awareness without full file bodies. |
MIN_CONDENSE_THRESHOLD |
Minimum user-configurable condensation trigger percentage (5). Defined in condense/index.ts. |
MAX_CONDENSE_THRESHOLD |
Maximum user-configurable condensation trigger percentage (100). Defined in condense/index.ts. |
| Synthetic Tool Results | Injected via injectSyntheticToolResults() to handle orphan tool calls before summarization. Prevents API rejections from providers (like OpenAI) that disallow conversations with unmatched tool_use blocks. |
SUMMARY_PROMPT |
System-level constant prefix prepended to every condensing API call. Disables tool calls and re-frames the task as summarization-only. Defined in condense/index.ts. |
SummarizeResponse |
The return type of summarizeConversation(): { messages, summary, cost, newContextTokens?, error?, errorDetails?, condenseId? }. |
ContextManagementResult |
Superset of SummarizeResponse returned by manageContext(): adds prevContextTokens, truncationId?, messagesRemoved?, and newContextTokensAfterTruncation?. |
| Effective API History | The subset of messages actually sent to the model, computed by getEffectiveApiHistory(). Filters out messages with active condenseParent or truncationParent tags and removes orphan tool_result blocks. |
Terms related to system prompt assembly in packages/core/src/prompts/system.ts and packages/core/src/prompts/sections/.
| Term | Description |
|---|---|
| system prompt | The full instruction text assembled at runtime and sent as the first message to the LLM. Composed of ~11 sections generated by individual files in packages/core/src/prompts/sections/. |
| generatePrompt | Internal async function in system.ts that concatenates all section outputs into the final system prompt string. Not exported directly — called by SYSTEM_PROMPT. |
| SYSTEM_PROMPT | Exported async function in system.ts that serves as the public entry point for prompt generation. Resolves mode metadata (getModeBySlug, getModeSelection), resolves PromptComponent overrides, then delegates to generatePrompt. Called by the task runner whenever a new conversation starts or context is condensed. |
| system prompt section | One composable fragment of the system prompt generated by a single function in packages/core/src/prompts/sections/. Each section is self-contained and concatenated in a fixed order. |
| section barrel | sections/index.ts — re-exports all section generator functions so system.ts can import them from a single path ("./sections"). |
| PromptComponent | Type from @shofer/types representing custom mode prompt overrides: { roleDefinition?: string, baseInstructions?: string }. Resolved by getPromptComponent(). |
| CustomModePrompts | Type from @shofer/types mapping mode slugs (e.g., "code", "architect") to PromptComponent overrides. Passed as customModePrompts to SYSTEM_PROMPT. |
| getPromptComponent | Exported helper in system.ts that looks up a mode's PromptComponent from CustomModePrompts, filtering out empty objects. |
| SystemPromptSettings | Type carrying settings relevant to prompt generation. Includes at minimum isStealthModel (controls vendor-confidentiality rules in rules.ts) and enableSubfolderRules (controls subfolder rule loading in custom-instructions.ts). Used by getRulesSection() and addCustomInstructions(). |
| roleDefinition | The opening statement of the system prompt that defines the LLM's persona. Set per-mode from modes.ts built-in definitions or from .shofer/shofermodes custom modes. Example: "You are Shofer, a highly skilled software engineer…". |
| baseInstructions | Per-mode instruction text from the PromptComponent, injected at the start of custom instructions (before user/global rules). Resolved alongside roleDefinition via getModeSelection() in system.ts. |
| shouldIncludeMcp | Boolean computed in system.ts as hasMcpGroup && hasMcpServers. Gates whether MCP server info is injected into the capabilities section. |
| effectiveProtocol | Constant "native" in system.ts with the comment "Tool calling is native-only." Suppresses XML tool-calling markup because the current implementation uses provider-native tool schemas. |
| toolsCatalog | Always-empty string ("") in system.ts with the comment "Tools catalog is not included in the system prompt." Tools are provided via the provider-native tool-calling mechanism, not inline text. |
Orphan tool_result Blocks |
tool_result blocks whose tool_use_id references a tool_use in a condensed-away message. Filtered out by getEffectiveApiHistory() to keep the API conversation valid. |
| Term | Description |
|---|---|
| TelemetryService | Singleton (TelemetryService.ts) that fans out telemetry events to all registered clients. Created via TelemetryService.createInstance(clients?). |
| TelemetryClient | Interface (telemetry.ts) that all telemetry backends implement: capture(event), captureException(error, props?), updateTelemetryState(bool), isTelemetryEnabled(), shutdown(). |
| PostHogTelemetryClient | Primary Node.js telemetry backend (PostHogTelemetryClient.ts). Uses posthog-node. Filters git repository properties. Gated behind TELEMETRY_ENABLED=true. |
| TelemetryClient (webview) | Browser-side singleton (TelemetryClient.ts) using posthog-js for UI interaction tracking. |
| BaseTelemetryClient | Abstract base class (BaseTelemetryClient.ts) implementing event subscription, property enrichment, and privacy filtering hooks. |
| TelemetryPropertiesProvider | Interface (telemetry.ts) implemented by ShoferProvider to supply auto-enriched properties to every event. |
| TelemetrySetting | Three-state user preference: "unset", "enabled", "disabled". "unset" is treated as disabled. |
| TelemetryEventName | Enum of all canonical telemetry event names. Must be used via TelemetryService.instance.capture<EventName>(...) typed wrappers. |
| TELEMETRY_ENABLED | Environment variable that acts as the global kill-switch. When false, TelemetryService never initializes and all telemetry is a no-op. |
| captureException | Typed exception reporting path. Auto-extracts properties from ApiProviderError and ConsecutiveMistakeError, filters expected errors (402/429). Mutates error.message. |
| TELEMETRY_SETTINGS_CHANGED | Meta-event fired when the user toggles telemetry. Emitted BEFORE updateTelemetryState(false) on OFF, AFTER on ON. |
| ApiProviderError | Structured error class carrying provider, modelId, operation, errorCode. |
| ConsecutiveMistakeError | Structured error class carrying taskId, consecutiveMistakeCount, consecutiveMistakeLimit, reason. |
| EXPECTED_API_ERROR_CODES | Set {402, 429} of HTTP status codes excluded from telemetry. |
| MCPASYNC_CALL* | Four lifecycle events for async MCP tool calls dispatched via call_mcp_tool_async. |
| PLUGIN_EVENT | The single catalog entry every plugin's telemetry arrives under (ctx.host.telemetry.capture), tagged plugin + event with scrubbed primitive properties. |
| Two-Phase Telemetry Gating | PostHogTelemetryClient requires BOTH VSCode global telemetry = "all" AND user telemetrySetting ≠ "disabled". |
| Property Enrichment | BaseTelemetryClient.getEventProperties() merges provider-supplied properties with event-specific properties. |
| Privacy Filtering | PostHogTelemetryClient.isPropertyCapturable() excludes repositoryUrl, repositoryName, defaultBranch. |
Terms used in code_stats.md to describe the project's development phases and statistical boundaries.
| Term | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
| Shofer Phase | The second development stage (Oct 2024 → Apr 2026, ~18 months, 6,261 commits). A full commercial product built on top of the Shofer skeleton. Covers the period from the Rename commit (6502b3cb2) to the last pre-Alexandros commit (67def7214). |
| Alexandros Phase | The current development stage (Apr 2026 → present), named after the new maintainer. Starts at commit 30a1c1fcb. |
| Stage Boundaries | The commit hashes partitioning the codebase into three statistical stages for line-count analysis. Defined in code_stats.md §"Stage Boundaries". |
| Codebase Size | Total source lines at a given commit boundary, excluding lockfiles, locales, snapshots, dist, SVG, and CHANGELOG. Computed via git ls-tree -r <commit> | grep -v ... | xargs git show | wc -l. The three measured boundaries are End of Shofer (385c54d3c), Pre-Alexandros (67def7214), and HEAD. |
Terms related to Shofer's configuration system, discovered during
the configuration.md verification.
| Term | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| VS Code configuration | Settings declared in src/package.json contributes.configuration.properties. These settings have a VS Code-inferred JSON schema (.type, .minimum, .maximum), appear in the VS Code Settings UI, and are read via vscode.workspace.getConfiguration("shofer.*") or (preferably) ContextProxy. |
| Global Settings (JSON-only) | Settings declared in globalSettingsSchema (Zod schema) and stored in VS Code globalState via ContextProxy. They have no settings-panel rows and must be configured by editing settings.json directly. Globally disabled by default — they appear only if the user has set them. |
| ContextProxy | Typed accessor singleton at ContextProxy.ts that unifies reads from VS Code configuration and globalState/secrets. Exposes getValue(key), getSecret(key), getAllGlobalState(). The Typed Settings Rule requires all extension settings access go through it. |
| Configuration key | A dot-separated identifier like shofer.allowedCommands that identifies a single setting. Keys in contributes.configuration use the shofer.* prefix; keys in globalSettingsSchema use camelCase names stored under the same shofer.* prefix in settings.json. |
| Configuration key source | Which backend a setting lives in. A setting can be VS Code-only (shofer.allowedCommands), GlobalState-only (shofer.useAgentRules), or dual-source (shofer.enableLlmProviderIntegration, which exists in both package.json and globalSettingsSchema). The GlobalState copy is what ContextProxy.getValue() serves at runtime. |
| Dual-source setting | A setting declared in BOTH package.json contributes.configuration AND globalSettingsSchema. Editing it through the VS Code settings UI updates the first copy; editing settings.json directly for the ContextProxy key updates the second. The two can drift. |
| devmand prefix | A prefix found on two dead package.json configuration keys: shofer.devmandExecutionTimeout and shofer.devmandTimeoutAllowlist. These have zero references in any TypeScript source file. The functional equivalents live in globalSettingsSchema as commandExecutionTimeout and commandTimeoutAllowlist. |
| Dead configuration key | A contributes.configuration property in package.json that has zero consumer references in the TypeScript source tree. Appears in the VS Code settings UI but changing it has no effect. | ## Appendix: Quick Reference |
When communicating about the UI, use these names:
- The task dropdown at the top of the chat → TaskSelector (not "task switcher" or "task menu")
- The chat input bar at the bottom → ChatTextArea (not "input box" or "composer")
- The mode dropdown in the input bar → ModeSelector (not "mode picker" or "mode switcher")
- The API config dropdown in the input bar → ApiConfigSelector (not "provider dropdown")
- The auto-approve settings in the input bar → AutoApproveDropdown
- The code index status badge in the input bar → IndexingStatusBadge (not "RAG badge" or "indexing indicator")
- The live memory status badge in the input bar → LiveMemoryStatusBadge (a plugin
chat-input-toolbarcontribution; not "assistant badge" or "agent indicator") - The file changes panel → FileChangesPanel (not "changed files list" or "diff panel")
- The queued messages section → QueuedMessages (not "message queue")
- The context window bar in the header → ContextWindowProgress (not "context usage bar")
- The task title in the header → TaskHeader (not "task info bar")
- The history panel → HistoryView (not "task list" or "history page")
- The settings panel → SettingsView (not "settings page" or "config page")
- The welcome screen → WelcomeView (not "splash screen" or "landing page")