Files
opencode-obsidian/openspec/project.md
2026-01-04 21:32:03 +00:00

4.7 KiB

Project Context

Purpose

Obsidian plugin that embeds the OpenCode AI assistant via an iframe. The plugin spawns a local OpenCode server process and displays its web UI in the Obsidian sidebar, enabling AI-assisted coding and note-taking within Obsidian.

Tech Stack

  • TypeScript - Primary language with strict null checks
  • Obsidian Plugin API - For UI integration, views, settings, and commands
  • esbuild - Bundler (ES2018 target, CommonJS output)
  • Node.js child_process - For spawning the OpenCode server process
  • Bun - Package manager and runtime

Project Conventions

Code Style

Imports:

  • ES modules with named imports
  • Order: Obsidian API → Node.js builtins → local modules
  • Use type keyword for type-only imports
  • Relative paths with ./ prefix
import { Plugin, WorkspaceLeaf, Notice } from "obsidian";
import { spawn, ChildProcess } from "child_process";
import type OpenCodePlugin from "./main";
import { OpenCodeSettings, DEFAULT_SETTINGS } from "./types";

Naming Conventions:

Type Convention Example
Classes PascalCase OpenCodePlugin, ProcessManager
Interfaces/Types PascalCase OpenCodeSettings, ProcessState
Constants UPPER_CASE or camelCase DEFAULT_SETTINGS, OPENCODE_VIEW_TYPE
Variables/functions camelCase getVaultPath, startServer
Private members camelCase (no prefix) private processManager
Files PascalCase for classes ProcessManager.ts, OpenCodeView.ts

TypeScript Patterns:

  • strictNullChecks enabled - always handle null/undefined
  • Union types for state: "stopped" | "starting" | "running" | "error"
  • async/await over raw Promises
  • Explicit return types on public methods

Architecture Patterns

Project Structure:

src/
├── main.ts           # Plugin entry, extends Plugin
├── types.ts          # Types and constants
├── OpenCodeView.ts   # Sidebar view (ItemView) with iframe
├── ProcessManager.ts # Server process lifecycle
├── SettingsTab.ts    # Settings UI (PluginSettingTab)
└── icons.ts          # Custom icon registration

Obsidian Patterns:

  • Extend Plugin with onload()/onunload() lifecycle
  • Extend ItemView for views: getViewType(), onOpen(), onClose()
  • Extend PluginSettingTab for settings: display()
  • DOM helpers: createEl(), createDiv(), setIcon()
  • Register in onload(), clean up in onunload()

State Management:

  • Callback-based subscriptions for state changes
  • Centralized state in manager classes (ProcessManager)
  • Immediate notification on state change via callbacks

Error Handling:

  • try/catch for async operations
  • console.error() for debugging
  • new Notice() for user-facing errors
  • Boolean returns for success/failure
  • Silent catch for non-critical ops (health checks)

Testing Strategy

Not currently configured. If adding tests:

  • Use Vitest for test runner
  • Place tests in src/__tests__/ or *.test.ts files
  • Add ESLint with @typescript-eslint/parser for linting

Git Workflow

Standard feature branch workflow. Commit messages should be concise and describe the change.

Domain Context

OpenCode Server:

  • OpenCode is an AI assistant CLI that can run as a web server
  • The plugin spawns opencode serve with port/hostname/CORS flags
  • Server health is checked via /global/health endpoint
  • Project directory is encoded as base64 in the URL path

Obsidian Integration:

  • View is registered with OPENCODE_VIEW_TYPE constant
  • Opens in right sidebar by default
  • Supports lazy start (starts server when view opens)
  • Auto-start option available in settings

Process States:

  • stopped - Server not running
  • starting - Server spawn initiated, waiting for health check
  • running - Server healthy and responding
  • error - Server failed to start or crashed

Important Constraints

Desktop Only:

  • Uses Node.js APIs (child_process.spawn()) unavailable on mobile
  • File system access via vault adapter requires desktop
  • Check for desktop environment before adding mobile-incompatible features

Build Output:

  • Must produce single main.js file (CommonJS format)
  • External: obsidian, electron, CodeMirror modules, Node.js builtins

TypeScript Config:

  • Target: ES6
  • Module: ESNext (bundled to CJS)
  • Strict null checks enabled
  • No implicit any

External Dependencies

Runtime:

  • OpenCode CLI must be installed on user's system (configurable path)
  • Default port: 14096, hostname: 127.0.0.1

Development:

  • obsidian - Obsidian API types and runtime
  • @types/node - Node.js type definitions
  • esbuild - Build bundler
  • typescript - Type checking