Skip to content

Latest commit

 

History

History
653 lines (511 loc) · 29.6 KB

File metadata and controls

653 lines (511 loc) · 29.6 KB

Codex Context Document

Last Updated: 2026-04-04

Project Overview

  • Name: Claudesidian MCP
  • Version: 5.11.1
  • Type: Obsidian Community Plugin
  • Purpose: MCP integration for Obsidian with AI-powered vault operations
  • Architecture: Agent-Tool pattern with domain-driven design
  • Stack: TypeScript, Node.js, Obsidian Plugin API, MCP SDK

Obsidian Plugin Development Guidelines

This is an Obsidian community plugin that must follow official Plugin Guidelines. All code changes must adhere to these best practices.

Plugin Lifecycle

// Plugins extend the Plugin base class
export default class MyPlugin extends Plugin {
    async onload() {
        // Initialize UI, register commands, set up events
        // Use registration methods for auto-cleanup
    }

    async onunload() {
        // Clean up resources (most handled automatically)
    }
}

Key lifecycle rules:

  • All registration methods (registerEvent, addCommand, registerView, registerInterval) auto-cleanup on unload
  • Never store view references in the plugin instance (causes memory leaks)
  • Use this.app.workspace.onLayoutReady() to defer startup operations

Styling - ALL STYLES IN styles.css

CRITICAL: All styles must be defined in styles.css, never inline in TypeScript/JavaScript.

// ❌ NEVER do this
element.style.color = 'white';
element.style.backgroundColor = 'red';
element.style.display = 'flex';

// ✅ ALWAYS do this
element.addClass('my-plugin-element');
/* In styles.css - use CSS variables for theme compatibility */
.my-plugin-element {
    color: var(--text-normal);
    background-color: var(--background-primary);
    display: flex;
}

Required CSS Variables (never hardcode colors):

Variable Purpose
--text-normal, --text-muted, --text-faint Text colors
--text-accent Interactive/link text
--background-primary, --background-secondary Background colors
--background-modifier-border Borders
--background-modifier-error Error states
--interactive-accent, --interactive-accent-hover Buttons/interactive
--radius-s, --radius-m, --radius-l Border radius

Security Requirements

innerHTML is FORBIDDEN with dynamic content:

// ❌ NEVER - XSS vulnerability
element.innerHTML = userProvidedContent;
element.innerHTML = `<div>${dynamicData}</div>`;

// ✅ Safe patterns
element.textContent = userProvidedContent;  // For text
element.createEl('div', { text: dynamicData });  // Obsidian API

// ✅ Safe innerHTML patterns (only these are acceptable)
element.innerHTML = '';  // Clearing
const escaped = div.innerHTML;  // Reading already-escaped content

Safe DOM creation with Obsidian API:

// Use createEl, createDiv, createSpan
const container = contentEl.createDiv({ cls: 'my-container' });
const heading = container.createEl('h2', { text: 'Title' });
const button = container.createEl('button', {
    text: 'Click me',
    cls: 'my-button'
});

// For icons, use setIcon
import { setIcon } from 'obsidian';
setIcon(button, 'chevron-right');

Event Registration

Always use registerDomEvent for DOM events:

// ❌ NEVER - causes memory leaks on unload
element.addEventListener('click', handler);
document.addEventListener('keydown', handler);
window.addEventListener('resize', handler);

// ✅ ALWAYS - auto-cleanup on unload
this.registerDomEvent(element, 'click', handler);
this.registerDomEvent(document, 'keydown', handler);
this.registerDomEvent(window, 'resize', handler);

// ✅ For Obsidian workspace events
this.registerEvent(this.app.vault.on('modify', handler));
this.registerEvent(this.app.workspace.on('active-leaf-change', handler));

File Operations

// ❌ NEVER use vault.adapter directly (mobile incompatible)
await this.app.vault.adapter.read(path);
await this.app.vault.adapter.write(path, content);

// ✅ Use Vault API
await this.app.vault.read(file);
await this.app.vault.cachedRead(file);  // Faster, uses cache

// ✅ For modifying files, use Vault.process() (atomic, prevents conflicts)
await this.app.vault.process(file, (content) => {
    return content.replace('old', 'new');
});

// ✅ Use Editor API for active file (preserves cursor)
const editor = this.app.workspace.activeEditor?.editor;
if (editor) {
    editor.replaceRange('new text', from, to);
}

Exception: vault.adapter is acceptable for storage paths that Obsidian does not index or that must be addressed directly, including hidden legacy paths and configured Nexus data roots. Normalize paths first and keep storage roots settings-derived; do not hardcode .nexus.

API Best Practices

Task Do This Not This
HTTP requests requestUrl() fetch()
Path handling normalizePath(userPath) Direct string concat
OS detection Platform.isMobile, Platform.isDesktop User agent sniffing
File lookup vault.getFileByPath(path) Iterating vault.getFiles()
View access workspace.getActiveViewOfType(MarkdownView) workspace.activeLeaf.view

Commands

this.addCommand({
    id: 'my-action',  // Don't duplicate plugin ID
    name: 'My action',  // Sentence case, no "command" word
    // NO default hotkey - users set their own
    checkCallback: (checking) => {
        const view = this.app.workspace.getActiveViewOfType(MarkdownView);
        if (view) {
            if (!checking) {
                // Execute command
            }
            return true;
        }
        return false;
    }
});

Mobile Compatibility

import { Platform } from 'obsidian';

if (Platform.isMobile) {
    // Mobile-specific code
}

// ❌ These APIs are NOT available on mobile
import { fs, path, crypto } from 'node:*';  // Node.js modules
require('electron');  // Electron APIs

// ✅ Mobile alternatives
// Use SubtleCrypto instead of crypto
// Use navigator.clipboard instead of electron clipboard
// Set isDesktopOnly: true in manifest if Node.js required

Accessibility Requirements

// ✅ Interactive elements need aria-labels
const iconButton = container.createEl('button', { cls: 'icon-button' });
iconButton.setAttribute('aria-label', 'Open settings');
setIcon(iconButton, 'settings');

// ✅ Keyboard navigation (Tab, Enter, Space)
// ✅ Focus indicators with :focus-visible
// ✅ Touch targets minimum 44×44px on mobile

Code Quality Rules

Rule Requirement
Type safety No as any casts, use instanceof checks
Variables Use const/let, never var
Console logging No console.log in production, only console.error for actual errors
UI text Sentence case everywhere
Cleanup Remove all template/sample code before submission

Manifest Requirements

{
    "id": "my-plugin-id",      // Lowercase, no "obsidian", doesn't end with "plugin"
    "name": "My Plugin Name",  // No "Obsidian" or "Plugin" suffix
    "version": "1.0.0",
    "minAppVersion": "1.0.0",
    "description": "Does something useful.",  // <250 chars, ends with punctuation
    "author": "Author Name",
    "isDesktopOnly": false     // true only if Node.js APIs required
}

Performance Guidelines

// ❌ Vault 'create' fires for ALL files on startup
this.registerEvent(this.app.vault.on('create', handler));

// ✅ Wait for layout ready
this.app.workspace.onLayoutReady(() => {
    this.registerEvent(this.app.vault.on('create', handler));
});

// OR check inside handler
onCreate(file: TFile) {
    if (!this.app.workspace.layoutReady) return;
    // Process event
}

References

Mockup Practice

Substantial UI work gets a standalone mockup in docs/mockups/ before any production code: new views, panels, modals, settings tabs, chat surfaces, and layout refactors. A tweak inside an existing layout does not — say so and implement.

Do not improvise the process from this note. The nexus-ui-mockups skill is the source of truth for how a mockup is built, revised, validated and handed off as a plan's visual contract — load it before starting, and follow its protocols and its check_mockup.py validator.

Implementation is a separate job under src/ and is governed by CLAUDE.md's hard rules (styles.css, registerDomEvent, no dynamic innerHTML). Mockup-only liberties never travel into plugin code.

Recent Milestones

March 2026

Mar 4: New Models + Bug Fixes ✅ (v4.4.5 → v4.4.6)

  • Added Codex Sonnet 4.6, Gemini 3.1 Pro/Flash Lite, GPT-5.3 Chat/Codex; removed legacy Codex 4 Opus/Sonnet
  • Fixed ConversationTitleModal focus trap: replaced fragile setTimeout/rAF hack, added focus restoration in onClose()
  • Fixed default temperature not loading from user settings (hardcoded 0.5 → reads defaultTemperature)
  • Fixed prompt selector using name instead of id as dropdown key (wouldn't persist selection)
  • Fixed syncWorkspacePrompt() saving name instead of id

February 2026

Feb 28: Dynamic Image Model Defaults ✅ (v4.4.4)

  • Image generation defaults now resolve from user settings instead of hardcoded values
  • Priority chain: explicit param > user settings > first available provider/model > fallback
  • generateImage: new resolveDefaults(), getAvailableProviderNames(), dynamic schema/errors
  • executePrompts/promptParser/RequestExecutor: removed hardcoded model lists and google-only restrictions
  • ImageGenerationService: added getInitializedProviders()
  • executeTypes: provider optional + accepts openrouter, model widened to string

Feb 26: Dynamic Image Model Loading ✅ (v4.4.3)

  • Image model dropdowns now load dynamically from adapters (removed hardcoded IMAGE_MODELS in ChatSettingsRenderer)
  • generateImage tool schema builds model enum at runtime from configured providers
  • Added getModelsForProvider() and getSupportedModelIds() to ImageGenerationService
  • Adding a new image model to an adapter now auto-populates UI and tool schema

Feb 26: New Image Models + FLUX Validation Fix ✅ (v4.4.2)

  • Added gemini-3.1-flash-image-preview (Nano Banana 2): Google direct + OpenRouter, 512px-4K, 14 ref images, new aspect ratios (1:4, 4:1, 1:8, 8:1)
  • Added gpt-5-image (OpenRouter only): GPT-5 with image generation, 400K context
  • Fixed FLUX models (flux-2-pro, flux-2-flex) failing validation — missing from supportedModels and ImageModel union type

Feb 23: Workspace Settings Display Fix ✅ (v4.4.1)

  • Root cause: renderWorkspacesTab() passed stale prefetchedWorkspaces (populated before SQLite ready) → WorkspacesTab skipped async load, showed JSONL fallback data only
  • Fix: pass prefetchedWorkspaces: null → WorkspacesTab always shows loading skeleton → awaits both workspaceService + hybridStorageAdapter → queries SQLite with full data
  • Also removed temporary [DEBUG-WS] console.error logs from 6 files: SettingsView.ts, WorkspacesTab.ts, ServiceManager.ts, WorkspaceService.ts, BackgroundProcessor.ts, PluginLifecycleManager.ts

Feb 22: Tool Call History Fix ✅ (v4.4.0)

  • MessageStreamHandler.ts — post-loop safety net: forces state=complete + accumulated toolCalls onto in-memory message before second save runs; prevents stale draft/null from overwriting good data
  • ConversationService.ts — try-catch around JSON.parse(tc.function.arguments) in convertToLegacyConversation; malformed JSON no longer crashes entire conversation load
  • MessageRepository.ts — defensive try-catch in rowToMessage() for toolCallsJson/metadataJson/alternativesJson
  • Note for existing stale conversations: Use the Nexus: Rebuild cache command to force SQLite cache rebuild from the synced event store; tool calls will reappear if present in JSONL.

Feb 22: TypeScript Build Fix ✅ (PR #31)

  • IPCTransportManager.ts — changed socket param from NodeJS.ReadWriteStream to net.Socket; removed 4 redundant casts
  • npm run build (tsc + esbuild) now passes clean

Feb 22: OpenAI CORS Bypass + Validation Fixes ✅ (PR #29)

  • nodeFetch.ts — Node.js https.request() passed as custom fetch to OpenAI SDK; bypasses CORS on /v1/responses
  • Fixed 3 stale validation probes: gpt-5-nano needs max_completion_tokens; Codex-3-5-haiku-latest deprecated → Codex-haiku-4-5-20251001
  • 619 tests (adds 55 nodeFetch unit tests)

Feb 22: Provider OAuth Connect ✅ (PR #26 — v4.3.4)

  • OpenAI Codex OAuth via ChatGPT: connect button, token refresh, model listing with (ChatGPT) suffix
  • Codex Responses API gotchas (CRITICAL):
    • No previous_response_id support — must use stateless full input array continuation
    • delta is plain string, not object — typeof event.delta === 'string' check required
    • CORS from app://obsidian.md — must use Node.js require('https').request() not fetch()
    • for await unreliable in Electron — use explicit chunkQueue/chunkWaiter event-listener queue
    • instructions field always required — cannot be conditional on conversationHistory
    • Model won't use tools without tool_choice: "auto" + explicit tool-use preamble in instructions
  • 547 tests passing, all console.log removed, JSON.parse in try-catch, expires_in validated

Feb 21: IPC Transport Fix ✅ (v4.3.2 — cherry-pick from PR #24, DylanLacey)

  • Fixed handleSocketConnection never wiring socket close/end to transport.close()
  • Crashed connectors no longer permanently wedge Protocol._transport; reconnects cleanly
  • FD leak on failed connect() also fixed (socket destroyed on rejection)
  • PR #24 mux part still open — pending contributor fix for hardcoded socket path

Feb 20: New Model Definitions ✅ (PR #22 — v4.3.1)

  • Added Codex Sonnet 4.6 (Codex-sonnet-4-6): 200K ctx, 64K out, $3/$15/M + 1M beta variant
  • Added Gemini 3.1 Pro Preview (gemini-3.1-pro-preview): 1M ctx, 65K out, $2/$12/M
  • Updated: AnthropicModels.ts, GoogleModels.ts, OpenRouterModels.ts

Feb 9: Conversation Memory Search ✅ (PR #19 — merged)

  • Semantic search across conversation turns and tool call traces via searchMemory tool
  • Two modes: Discovery (workspace-scoped) and Scoped (session-filtered, N-turn window)
  • QA pair model + ContentChunker (500-char/100-overlap) + sqlite-vec KNN + multi-signal reranking
  • Real-time indexing via ConversationEmbeddingWatcher + background backfill
  • Actionable error feedback, enhanced descriptions, optional workspaceId
  • EmbeddingService refactored: facade pattern (1034→199 lines) + 3 domain services
  • MemorySearchProcessor (824→553) and IndexingQueue (822→497) split into extracted modules
  • 351 tests pass (205 new), all coverage thresholds met, 19 commits
  • Plan: docs/plans/conversation-memory-search-plan.md
  • Review: docs/review/pr19-conversation-memory-search.md

Feb 5: Startup Performance Fix ✅ (PR #15)

  • Non-blocking startup ~200ms (75x improvement from ~15s)
  • Root cause: deadlock between ChatView.onOpen() and onLayoutReady
  • Solution: setTimeout(0) services, registerViewEarly(), non-blocking onOpen()

Feb 5: Chat Stop/Retry/Branch Bug Fixes ✅ (PR #16)

  • 12 bugs fixed across stop, retry, and branch navigation
  • Key patterns: clear-and-restream, incremental reconciliation, dual abort controllers
  • 142 unit tests across 7 new test files

Feb 5: Inline AI Editing Feature ✅ (PR #14)

  • Right-click or hotkey to edit selected text via LLM
  • State machine pattern, streaming preview, Jest test infrastructure (41 tests)

January 2026

Jan 24: ExecutePrompts improvements (optional provider/model, reference images, CommandManager cleanup) Jan 12: MCP integration settings fix (invalid config handling) Jan 4: CanvasManager agent (4 tools), SQLite transaction fix, memory leak fixes (7), embeddings toggle

December 2025

Dec 22: Subagent UI + architecture Dec 20: Auto-compaction + dual models + WebLLM Dec 17: Two-Tool Architecture (95% token reduction) Dec 16: Local embeddings + dead code cleanup (~4,000 lines removed) Dec 9: Mobile + branching persistence Dec 3: SQLite + JSONL hybrid storage

Quick Navigation

Core Directories

  • /src/agents/ - Agent implementations (PromptManager, ContentManager, etc.)
  • /src/services/ - Shared services (LLM providers, memory, conversations)
  • /src/components/ - UI components (chat view, settings, modals)
  • /src/types/ - TypeScript type definitions
  • /src/utils/ - Utility functions and helpers

Key Files

  • main.ts - Plugin entry point and lifecycle management
  • connector.ts - MCP server connector for Codex Desktop
  • src/agents/index.ts - Agent registry and initialization
  • src/services/conversationService.ts - Chat conversation management
  • src/services/llmService.ts - LLM provider abstraction layer

Agent Architecture

Available Agents

ToolManager (src/agents/toolManager/) - MCP Entry Point (Two-Tool Architecture)

  • getTools: Discovery - returns tool schemas for requested agents/tools
  • useTools: Execution - unified context-first tool execution
  • Only these 2 tools are exposed to Codex Desktop. All other agents work internally.

Tool names below are the CLI form (agent tool-name, kebab-case) — what a caller actually types and what getTools/useTools resolve. Verify against src/agents/** (slug:) before trusting; the /nexus-release skill gates on refreshing this list, and tests/unit/shippedGuidanceCommands.test.ts fails when shipped docs name a tool that does not exist.

  1. PromptManager (src/agents/promptManager/) - Custom prompts and LLM integration

    • prompt: execute, create, get, list, update, archive, sub, list-models, generate-image, generate-audio, generate-video, check-generated-artifact
    • No delete — the AI gets archive (reversible). Media generation is async: generate-* returns a job, poll check-generated-artifact <jobId>.
  2. ContentManager (src/agents/contentManager/) - Note reading/editing operations

    • content: read, write, replace, insert, set-property
    • read requires --start-line. replace is pattern-anchored {path, start, end, content} — anchor TEXT, not line numbers.
  3. StorageManager (src/agents/storageManager/) - File/folder management

    • storage: list, create-folder, move, copy, archive, open
  4. SearchManager (src/agents/searchManager/) - Advanced search operations

    • search: content, directory, memory, query-notes
  5. MemoryManager (src/agents/memoryManager/) - Workspace/state/workflow management

    • memory: create-workspace, list-workspaces, search-workspaces, load-workspace, update-workspace, archive-workspace, create-state, list-states, load-state, update-state, archive-state, run
    • No session tools — sessions are context fields, not tools. memory run triggers a workflow (--workflow-id/--workflow-name).
  6. CanvasManager (src/agents/canvasManager/) - Obsidian canvas operations

    • canvas: read, write, update, list
  7. TaskManager (src/agents/taskManager/) - Workspace-scoped project/task management with DAG dependencies

    • task: create-project, list-projects, update-project, archive-project, create, list, update, move, query, open, link-note
    • Note the asymmetry: project tools are suffixed (create-project), task tools are bare (create, list, update, move, query).
    • Services: TaskService (business facade), DAGService (pure computation)
    • Auto-loads task summary when workspace loads

Agent Structure Pattern

agents/
  [agentName]/
    [agentName].ts          # Main agent class extending BaseAgent
    tools/                   # Operation tools
      [toolName].ts         # File: read.ts, Class: ReadTool
      services/             # Tool-specific services
    services/               # Agent-level shared services
    types.ts                # Agent-specific types
    utils/                  # Agent-specific utilities

Base Classes

  • BaseAgent (src/agents/baseAgent.ts) - Common agent functionality
  • BaseTool (src/agents/baseTool.ts) - Common tool functionality with generic types
  • IAgent (src/agents/interfaces/IAgent.ts) - Agent interface contract
  • ITool (src/agents/interfaces/ITool.ts) - Tool interface contract

Current Context

Active Branch

main (current) — active worktrees:

  • .worktrees/fix-subagent-bugs (branch: fix/subagent-bugs) — pending manual test

Open PRs

# Title Status
#29 OpenAI CORS bypass + validation probe fixes Merged
#23 Plugin store compliance audit Awaiting manual test in Obsidian before merge
#24 Socket lifecycle fix (DylanLacey) Transport fix in main (v4.3.2); mux awaiting contributor socket path fix

Current Work

PR #23 — plugin store compliance (fix/plugin-store-audit-fixes): ready to merge, needs manual test PR (untracked) — subagent fixes (fix/subagent-bugs): 29 fixes, 372 tests passing, awaiting manual test

Branch Architecture

A branch IS a conversation with parent metadata:

  • metadata.parentConversationId: parent conversation
  • metadata.parentMessageId: message the branch is attached to
  • metadata.branchType: 'alternative' | 'subagent'

Key Files:

  • src/services/chat/BranchService.ts - Facade over ConversationService
  • src/ui/chat/controllers/SubagentController.ts - Subagent infrastructure
  • src/ui/chat/controllers/NexusLoadingController.ts - Loading overlays
  • src/ui/chat/services/ContextTracker.ts - Token/cost tracking

Known Issues

Workspace Delete Persistence (Feb 2):

  • Deleted workspaces may reappear on page reload
  • Backend delete logic looks correct, may be UI cache issue

Subagent Flow (Dec 22, fixed Feb 20 in fix/subagent-bugs — awaiting manual test):

  • 29 bugs fixed: icon race, retry-stuck, abort race, O(N) scan, Continue feature, EventBus instance-scoping, maxIterations enforcement, and more
  • Full fix list: docs/review/pr23-subagent-functionality-review.md

WebLLM/Nexus (Dec 20):

  • Multi-turn tool continuations may crash on Apple Silicon (WebGPU issue)
  • If startup hangs on "loading cache", clear site data

Backlog

  1. Obsidian Secrets API Adoption (target: March 2026): Migrate API key storage to SecretStorage API (v1.11.4+). Research: docs/preparation/obsidian-secrets-api-research.md
  2. Port 3000 conflict: Fixed OpenRouter OAuth port changed to 3456 (commit 15576fb2). MCPServer.ts HttpTransportManager still on 3000; long-term: make configurable.
  3. SOLID Audit: SystemPromptBuilder.ts and ModelAgentManager.ts are large files
  4. SQLiteCacheManager.ts (849 lines): Above 600-line threshold
  5. v5.0.0 Deprecation Cleanup: Remove backward compatibility for old dedicated agent structures (TODO(v5.0.0) in WorkspacePromptResolver)
  6. Obsidian CLI Integration (blocked: Catalyst-only): Research: docs/preparation/obsidian-cli-research.md
  7. Missing version-bump.mjs: package.json version lifecycle script references node version-bump.mjs but file doesn't exist — npm version will error. Either create it or remove the script reference.

Obsidian Plugin Guidelines Compliance

Status: All major issues addressed (Dec 2025). isDesktopOnly: false is correct (chat works on mobile, MCP requires desktop).

Issue Status
innerHTML security XSS fix applied (MessageEditController); 11 safe patterns remain
registerDomEvent Complete (15 more migrated Feb 20)
console.log cleanup 398 → 1 (ImageGenerationService.ts:55 pending)
Inline styles 85 → 13
Type safety (as any) 0 remaining (all 12 removed Feb 20)
@ts-ignore 1 remaining (documented)

Development Notes

Build Commands

  • npm run dev - Development build with watch mode
  • npm run build - Production build (TypeScript + esbuild)
  • npm run test - Run Jest test suite
  • npm run lint - Run ESLint
  • npm run deploy - Build and deploy via PowerShell script

Testing Approach

  • Unit Tests: Jest for core logic and services (619 tests total — 351 baseline + 268 OAuth/Codex/nodeFetch)
  • Integration Tests: Manual testing in Obsidian environment
  • MCP Testing: Via Codex Desktop connection

Code Patterns

  • Agents: Extend BaseAgent, register tools in constructor
  • Tools: Extend BaseTool<Params, Result>, implement execute(), getParameterSchema(), getResultSchema()
  • Results: Return { success: boolean, ...data } or { success: false, error: string }
  • Services: Singletons with dependency injection via constructor

Dependencies

See package.json. Key: MCP SDK, LLM provider SDKs (Anthropic, OpenAI, Google, Groq), express, winston, uuid.

Code Quality

SOLID Refactoring Progress (12/17 large files completed)

Key reductions: HybridStorageAdapter (-72%), LLMService (-75%), ChatService (-60%), LLMProviderModal (-82%), MessageBubble (-45%), EmbeddingService (-81% facade), MemorySearchProcessor (-33%), IndexingQueue (-40%)

Remaining Large Files (600+ lines)

ChatSettingsModal (702), ChatView (659), OpenRouterAdapter (640), ValidationService (625), BatchExecutePromptTool (618), GoogleAdapter (612)

MCP Integration

Server Configuration

  • Server runs locally via connector.js
  • Configured in Codex Desktop's claude_desktop_config.json
  • Server identifier: claudesidian-mcp-[vault-name]
  • Supports multiple vault instances simultaneously

Two-Tool Architecture

Instead of 50+ tools, MCP exposes just 2: getTools (discovery) and useTools (execution).

Context Schema: { workspaceId, sessionId, memory, goal, constraints? } - all required except constraints.

Flow: getTools → get schemas → useTools with the context fields at the top level plus a single tool string.

⚠️ The calls: [{agent, tool, params}] array and the nested context: {...} object were removed in v5.9.0 and are rejected outright (Deprecated payload shape).

Benefits: 95% token reduction (~15,000 → ~500), works with small context models.

Key Files: src/agents/toolManager/ (agent + tools), src/services/trace/ToolCallTraceService.ts

Tool Count: 60 tools across 9 agents (not counting ToolManager meta-tools)

Memory & Workspace System

Storage Location

Primary synced event store: settings-derived vault root, settings.storage.rootPath (default Nexus) with managed data under <rootPath>/data/:

  • conversations/<conversationId>/shard-*.jsonl - sharded append-only conversation events
  • workspaces/<workspaceId>/shard-*.jsonl - sharded append-only workspace/session/state/trace events
  • tasks/<workspaceId>/shard-*.jsonl - sharded append-only task/project events
  • _meta/ - storage and migration manifests

Configured root rules: resolve with resolveVaultRoot(settings, { configDir }); never hardcode Nexus except as DEFAULT_STORAGE_SETTINGS.rootPath, and never hardcode .nexus for new writes.

Legacy read paths: .obsidian/plugins/<plugin-folder>/data/, compatibility plugin folders (nexus, claudesidian-mcp), legacy .nexus/, and storage.previousRootPaths remain read/migration fallback sources. They are not the primary write target.

Local-only cache (auto-rebuilt from JSONL, never source of truth):

  • Desktop: IndexedDB-backed via IndexedDBCacheBlobStore
  • Mobile: vault.adapter file backend at .obsidian/plugins/<plugin-folder>/data/cache.db

Architecture

  • Hybrid JSONL + SQLite: sharded JSONL event store = source of truth, SQLite = rebuildable fast query/vector cache
  • True database pagination with OFFSET/LIMIT
  • Workspace-scoped sessions and traces
  • Searchable via MemoryManager and SearchManager agents

UI Components

  • Chat View: src/components/ChatView.ts - conversations, branching, streaming, tool accordion
  • Settings: src/components/ConfigModal.ts - tabbed LLM/agent configuration

Chat Suggesters

Trigger Purpose
/ Tool hints
@ Custom agents
[[ Note links
# Workspace data

Key files: src/ui/chat/components/suggesters/, MessageEnhancer.ts, SystemPromptBuilder.ts

Architectural Notes

  • Subagents: Branch → stream via LLMService → save result. chunk.toolCalls are display-only.
  • WebLLM/Nexus: Nexus Quark (4B, 4K context), <tool_call> format. May crash on Apple Silicon.
  • Storage: Branches as JSONL events, SQLite v4 schema, tool names use agent_tool format.
  • Apps & Vault Access: App agents now receive the full Obsidian App via BaseAppAgent.setApp(), which also wires in Vault. Use getVault() for file writes and getApp() when a tool needs workspace, command, or Web Viewer access. Use vault.createBinary() for binary outputs (audio, images, PDFs) and vault.create() for text files. Always ensure parent directories exist before writing. Follow the patterns established by ElevenLabs audio tools and the webTools app. For generated artifacts where the caller must choose the destination, prefer a required outputPath parameter.

Working Memory

Current Session

  • Resume: Codex --resume f2266b8f-b5ca-4b90-a87e-db0a0304ffd7
  • Team: pact-f2266b8f
  • Started: 2026-03-08 11:52:33 UTC