Local-first Windows agent runtime: desktop UI is optional, the runtime runs tray-only/headless, talks to a local LLM, and executes actions through an MCP tool server.
- Layered architecture: Frontend (WPF/tray/hotkeys) β Agent orchestrator β LLM client β MCP server (stdio JSON-RPC).
- Command Palette with three tabs: Chat, Memory Browser, and Profile/Nuggets.
- Memory system: facts, events, and text chunks stored in SQLite with hybrid BM25 + optional embeddings retrieval.
- Shallow memory personalization: Profile Cards for the user and people they mention, plus Memory Nuggets (atomic personal facts) injected into context at greeting and in-conversation.
- Tool routing pipeline: Intent Router (
RouterOutput) β Policy Gate (PolicyDecision) β conflict resolution matrix β tool loop executor. - Web search: DuckDuckGo HTML, Google News RSS, and SearXNG providers with smart query extraction.
- Conflict detection: Memory storage checks for duplicates, single-vs-multi-valued predicates, and antonym contradictions before writing.
- Runtime safety controls: global panic mode, fail-closed safe mode, strict MCP handshake validation, and configurable tool budgets.
- Control-plane MCP hooks:
health.check,capabilities.describe,policy.get_state,policy.set_panic_mode,audit.export_bundle. - Preview/apply contract: file and system tools support
_preview+_applypairs for explicit dry-run style execution. - Headless mode:
--headlessstarts without the overlay window (tray + hotkeys + background agent still run). - PTT voice pipeline: push-to-talk capture β local ASR (
faster-whisper) β agent response β local TTS playback via VoiceHost.- Cold-start optimization: Voice engine warms up in the background asynchronously to ensure an instant application splash/launch.
- Streaming latency: Aggressive phrase-based chunking provides ultra-low Time-To-First-Audio (TTFA).
- Audit log is always-on:
%LOCALAPPDATA%\SirThaddeus\audit.jsonl.
flowchart LR
subgraph frontend [Layer 1: Frontend β apps/desktop-runtime]
Tray[System Tray]
Overlay[WPF Overlay β optional]
PTT[Push-to-Talk]
TTS[Text-to-Speech]
Palette[Command Palette]
end
subgraph agent [Layer 2: Agent Orchestrator β packages/agent]
Loop[Agent Loop]
Context[Conversation History]
Router[Intent Router]
Gate[Policy Gate]
end
subgraph llm [Layer 3: LLM Client β packages/llm-client]
LmStudio[LM Studio / OpenAI-compatible]
end
subgraph memory [Memory β packages/memory + memory-sqlite]
Store[SQLite Store]
Retriever[Retriever β BM25 + embeddings]
end
subgraph mcp [Layer 4: MCP Tool Server β apps/mcp-server]
Server[MCP Server β stdio]
Tools[Memory / Browser / File / System / Screen / WebSearch]
end
PTT -->|audio file| Loop
Palette -->|typed request| Loop
Loop --> Router -->|RouterOutput| Gate
Gate -->|allowed tools| LmStudio
LmStudio -->|tool_calls| Loop
Loop -->|tools/call| Server
Server -->|tool result| Loop
Loop --> Retriever --> Store
Loop -->|final text| TTS
Loop -->|events| Overlay
Tray --> Overlay
| Layer | Project(s) | Responsibility | Talks to |
|---|---|---|---|
| Frontend | apps/desktop-runtime |
Hotkeys, tray, overlay, PTT capture trigger, TTS output, Chat/Memory/Profile UI | Agent orchestrator (in-process) |
| Agent | packages/agent |
Conversation loop, intent routing, policy gate, tool execution orchestration | LLM client + MCP client |
| LLM client | packages/llm-client |
OpenAI-style /v1/chat/completions + /v1/embeddings calls |
LM Studio HTTP server |
| Memory | packages/memory, packages/memory-sqlite |
Retrieval engine (BM25 + embeddings), scoring, gating, SQLite store | β |
| MCP server | apps/mcp-server |
Exposes tools over MCP stdio: memory, browser, file, system, screen, web search | Desktop runtime (child process) |
sir-thaddeus/
βββ apps/
β βββ desktop-runtime/ # WPF overlay + tray + hotkeys + PTT + TTS
β β βββ Converters/ # XAML value converters (Markdown, Base64, etc.)
β β βββ Services/ # Hotkey, MCP process, PTT, TTS, tray icon
β β βββ ViewModels/ # MVVM view models (Chat, Memory, Profile browsers)
β βββ voice-host/ # Local VoiceHost process (ASR/TTS HTTP surface)
β βββ voice-backend/ # Python ASR/TTS backend + model/voice assets
β βββ mcp-server/ # MCP tool server (stdio)
β βββ Tools/ # Memory, Browser, File, System, Screen, WebSearch
βββ packages/
β βββ agent/ # Agent orchestration loop + policy gate + router
β βββ llm-client/ # LM Studio / OpenAI-compatible client + embeddings
β βββ memory/ # Memory retrieval engine, scoring, intent classification
β βββ memory-sqlite/ # SQLite-backed IMemoryStore (WAL mode, FTS5)
β βββ web-search/ # Web search providers (DuckDuckGo, Google News, SearXNG)
β βββ config/ # %LOCALAPPDATA% settings.json management
β βββ core/ # State machine, runtime controller
β βββ audit-log/ # JSONL audit logging
β βββ permission-broker/ # Time-boxed permission token management
β βββ tool-runner/ # Tool execution with permission enforcement
β βββ invocation/ # Command planning/execution
β βββ observation-spec/ # Observation spec schema + validation
β βββ local-tools/
β βββ Playwright/ # Playwright browser tool (not MCP-wired yet)
βββ tests/ # Unit + integration tests
βββ tools/ # Dev utilities (PopulateTestMemory, etc.)
βββ project-notes/ # Design docs and notes
- Windows 10/11
- .NET SDK pinned in
global.json(currently9.0.305) - LM Studio (or any OpenAI-compatible local server)
- Default expected base URL:
http://localhost:1234 - Endpoints used:
/v1/chat/completions,/v1/embeddings(optional)
- Default expected base URL:
On first run, the desktop runtime creates:
- Settings:
%LOCALAPPDATA%\SirThaddeus\settings.json - Memory DB:
%LOCALAPPDATA%\SirThaddeus\memory.db - Audit log:
%LOCALAPPDATA%\SirThaddeus\audit.jsonl - PTT audio folder:
%LOCALAPPDATA%\SirThaddeus\audio\
Example settings file:
{
"llm": {
"baseUrl": "http://localhost:1234",
"model": "local-model",
"maxTokens": 2048,
"temperature": 0.7,
"systemPrompt": "You are a helpful assistant with access to local tools."
},
"audio": {
"pttKey": "F13",
"ttsEnabled": true
},
"ui": {
"startMinimized": false,
"showOverlay": true
},
"mcp": {
"serverPath": "auto"
},
"memory": {
"enabled": true,
"dbPath": "auto",
"useEmbeddings": true,
"embeddingsModel": ""
}
}Notes:
audio.pttKeysupportsF1..F24or hex virtual keys like0x7C.mcp.serverPath = "auto"resolves to the builtSirThaddeus.McpServer.exein the repo output folders.memory.dbPath = "auto"resolves to%LOCALAPPDATA%\SirThaddeus\memory.db.memory.embeddingsModeldefaults to the chat model if left empty.runtimeSafety.strictHandshakeenforces protocol/contract/manifest compatibility at startup (fail closed).runtimeSafety.panicModeblocks side-effect tool groups at runtime.toolBudgetsapplies hard per-turn/per-session/per-minute caps to reduce runaway tool loops.
Sir Thaddeus is local-first by design.
- Processing happens on your machine, with explicit outbound calls only through configured tools.
- No default telemetry pipeline is enabled in this repo.
- Audit logging is append-only and local (
%LOCALAPPDATA%\SirThaddeus\audit.jsonl).
- Event metadata (actor, action, timestamp, result)
- Tool call lifecycle events (start/end, duration, permission outcome)
- Redacted tool input/output summaries for diagnostics
- Raw secrets (tokens, API keys, passwords, cookies, bearer strings, connection strings)
- Full OCR dumps and full file contents
- Full
system_executecommand text in audit summaries (only executable name, argument count, and command hash)
- Settings:
%LOCALAPPDATA%\SirThaddeus\settings.json - Memory DB:
%LOCALAPPDATA%\SirThaddeus\memory.db - Audit log:
%LOCALAPPDATA%\SirThaddeus\audit.jsonl
# First-time setup / restore
.\dev\bootstrap.ps1
# Fast local loop (Debug build + tests)
.\dev\test.ps1
# Full suite (Release + restore) for pre-commit checks
.\dev\test_all.ps1
# Production preflight gate before release/distribution
.\dev\preflight.ps1
# Start the voice backend manually (for development)
.\dev\start-voice-backend.ps1 -TtsEngine kokoro -TtsVoiceId af_skyTesting details and filters are documented in README_TESTING.md.
Use the release packaging script from repo root:
.\dev\release-package.ps1 -Version v0.1.0This produces a self-contained win-x64 ZIP and checksum files under .\artifacts\release\.
The package includes README_FIRST_RUN.md and (when present) SirThaddeus.Settings.template.json.
To run the local test gate automatically before each push:
git config core.hooksPath .githooksThis enables .githooks/pre-push.cmd, which runs .\dev\test.ps1 and blocks pushes on failure.
- PR gate:
.github/workflows/ci-pr.yml(runs.\dev\test.ps1, uploads TRX artifacts) - Release gate:
.github/workflows/ci-release.yml(runs preflight, packages self-contained ZIP, and publishes release assets onv*tags) - SBOM gate:
.github/workflows/ci-sbom.yml(manual/tag-triggered SPDX SBOM artifact) - Dependency updates:
.github/dependabot.yml
dotnet run --project apps/desktop-runtime/SirThaddeus.DesktopRuntimedotnet run --project apps/desktop-runtime/SirThaddeus.DesktopRuntime -- --headlessYou can still show the overlay later from the tray menu.
dotnet run --project apps/mcp-server/SirThaddeus.McpServer| Shortcut | Action |
|---|---|
Ctrl+Space |
Open Command Palette |
F13 (default; configurable via settings) |
Push-to-Talk trigger (keyboard hook) |
| Tab | Purpose |
|---|---|
| Chat | Conversational interface to the agent. Tool calls, web search, and screen capture trigger from here. |
| Memory | Browse, filter, and CRUD facts, events, and chunks stored in SQLite. |
| Profile | Manage Profile Cards (user + people) and Memory Nuggets (atomic personal facts). Sub-panes: Profiles, Nuggets. |
| Tool | Description |
|---|---|
MemoryRetrieve |
Retrieves relevant memory (profile card, nuggets, facts, events, chunks). Supports mode=greet for cold start. |
MemoryStoreFacts |
Stores subject-predicate-object facts with conflict/duplicate detection. |
MemoryUpdateFact |
Updates an existing fact's object value (for conflict resolution). |
WebSearch |
Searches the web via DuckDuckGo, Google News RSS, or SearXNG. |
BrowserNavigate |
HTTP fetch + content extraction (Playwright available but not MCP-wired yet). |
FileRead |
Reads up to 1 MB from a local file. |
FileList |
Lists up to 100 entries in a directory. |
SystemExecute |
Runs allowlisted commands only. No raw shell execution. |
ScreenCapture |
Captures full screen or active window (explicit permission required). |
health.check |
Read-only control-plane health snapshot with dependency readiness. |
capabilities.describe |
Read-only manifest and capability summary for MCP tools. |
policy.get_state |
Read-only policy/runtime safety snapshot from current settings. |
policy.set_panic_mode |
Explicitly toggles panic mode (confirm=true required). |
audit.export_bundle |
Creates a redacted diagnostics bundle (confirm=true required). |
Use this list when you want reviewers to focus on architecture first, not implementation details:
- project-notes/architecture-review-index.md - quick index of design docs + review order
- project-notes/architecture-nuts-bolts.md - current runtime architecture, trust boundaries, wiring paths
- project-notes/mcp-tools-reference.md - current MCP tool contracts, permission model, and audit guarantees
- project-notes/tool-conflict-matrix.md - deterministic tool conflict resolution rules
- project-notes/tool-routing-v2.md - current routing pipeline notes + MCP hook points
- project-notes/architectural-design.md - product-level architecture strategy
- Playwright via MCP: Playwright tool exists, but MCP uses a simpler HTTP navigation tool for now.
- Voice cold-start latency: first-turn ASR/TTS may be slower while local models warm up.
- Nugget auto-suggest: V1 nuggets are manual-only. Two-sighting auto-suggest (V1.1+) is designed but deferred.
- README_TESTING.md - test harness usage and troubleshooting
- README_DEPLOY.md - production preflight and deployment checklist
- README_FIRST_RUN.md - end-user first-run flow for release ZIP builds
- project-notes/architecture-review-index.md - architecture docs index for review
- project-notes/github-branch-protection.md - required status checks and merge guard setup
- project-notes/code-signing.md - optional Authenticode signing guidance
See LICENSE file.