Skip to content

Latest commit

 

History

History
908 lines (748 loc) · 214 KB

File metadata and controls

908 lines (748 loc) · 214 KB

Shofer Terminology

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.


Table of Contents

  1. UI Components — Chat Area
  2. UI Components — Task Management
  3. UI Components — VS Code Panel Title Bar
  4. UI Components — Sidebar & Navigation
  5. UI Components — Panels & Overlays
  6. Architecture — Extension Host (Backend)
  7. Architecture — Webview (Frontend)
  8. Data Types & Schemas
  9. IPC Protocol
  10. Tools — Canonical Names
  11. Tool Groups (Categories)
  12. Modes
  13. Task States & Lifecycle
  14. Special Files & Directories
  15. API Provider Concepts
  16. Private Tool Provider System
  17. Telemetry Concepts
  18. Context Window Data Flow
  19. System Prompt Architecture
  20. Configuration Concepts

1. UI Components — Chat Area

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.

Image Attachment State

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.

2. UI Components — Task Management

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.

3. UI Components — VS Code Panel Title Bar

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 ascending N order.
  • 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/title entry and a new CommandId.
  • "Put it next to the Plus/Settings icons" → use a navigation@N group.
  • "Put it in the menu" → use an overflow@N group.
  • Do not confuse these with the React toolbar inside ChatTextArea (the webview input bar), which contains ModeSelector, ApiConfigSelector, AutoApproveDropdown, CommandsButton, SkillsButton, etc.

3a. UI Components — Sidebar & Navigation

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.


4. UI Components — Panels & Overlays

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.

5. Architecture — Extension Host (Backend)

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: isAutoApprovableAskautoApprovalEnabled 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. |


6. Architecture — Webview (Frontend)

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.

7. Data Types & Schemas

Defined in packages/types/src/. Always refer to the canonical type name.

Core Task Types

| 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. |

Chat Message Types

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.

Tool-Related Types

| 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_filewrite_to_file, search_and_replaceedit. | | 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. |

MCP (Model Context Protocol) Types

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.

Worktree Types

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.

State & Configuration Types

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).

Persisted Task Files

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).

Export Concepts

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.

8. IPC Protocol

Communication between the webview (React) and extension host (Node.js) uses typed discriminated unions.

Extension → Webview (ExtensionMessage)

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.

Webview → Extension (WebviewMessage)

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.

9. Tools — Canonical Names

Defined in tool.ts as the toolNames const. Always use these exact strings when referring to a tool:

File Operations

  • 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 via rm/mv subcommands.

Search & Exploration

  • 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.

Command Execution

  • execute_command — Run CLI commands with configurable cwd and timeout.
  • read_command_output — Retrieve full output from a truncated command execution.

Task Lifecycle

  • 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).

Content

  • fetch_web_page — Download and extract text from web pages.
  • view_image — View an image file.
  • generate_image — Generate an image via AI.

Workspace & Management

  • 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.

Worktree Slash Commands

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.

MCP

  • 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.

Deprecated Tool Names

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)

10. Tool Groups (Categories)

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.

Dynamic categories

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.

Renamed Groups (auto-translated by schema validation)

Old Name Canonical Name
edit write
command execute
modes mode

11. Modes

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.


12. Task States & Lifecycle

See also task_states.md.

State Resolution

The icon for a task (in TaskSelector and TaskHeader) is resolved as:

  1. runtime.state — live execution state from ManagedTask (in-memory), always wins if present.
  2. item.taskState — persisted state from HistoryItem (survives restarts).
  3. { lifecycle: "idle" } — default fallback.

State Indicator Colors

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

waiting vs waiting_input: waiting_input means the task is paused waiting for user approval or input (e.g., tool-approval prompt, ask_followup_question). waiting means the task is blocked on a non-user external event — parked in wait on its mailbox, or on an async MCP call via wait_for_mcp_call. Only waiting_input triggers a notification badge in the TaskSelector.

Visual Mapping (Codicons)

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.

CSS Custom Properties for State Indicators

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.

Restore Sanitization

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.

Key Task Events (emitted by Task)

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.

Cost Limit States

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.

13. Special Files & Directories

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.

15. Tool Preparation Progress Protocol

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. |

14. API Provider Concepts

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.tsglobalSettingsSchema minus taskHistory, listApiConfigMeta, and currentApiConfigName. Drives full-settings export.

14a. Context Window Data Flow

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.

15. Context Management Concepts

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.

17. System Prompt Architecture

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.

16. Telemetry Concepts

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.

18. Project History & Analysis

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. |


19. Configuration Concepts

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-toolbar contribution; not "assistant badge" or "agent indicator")
  • The file changes panelFileChangesPanel (not "changed files list" or "diff panel")
  • The queued messages sectionQueuedMessages (not "message queue")
  • The context window bar in the header → ContextWindowProgress (not "context usage bar")
  • The task title in the headerTaskHeader (not "task info bar")
  • The history panelHistoryView (not "task list" or "history page")
  • The settings panelSettingsView (not "settings page" or "config page")
  • The welcome screenWelcomeView (not "splash screen" or "landing page")