| name | obsidian-workspace-skill |
| description | Development conventions and architecture guide for the Obsidian plugin monorepo. |
Obsidian Workspace โ Repository Skill
Project Overview
A monorepo of Obsidian community plugins sharing a common architecture enforced by a boiler-template sync engine. All plugins follow a strict 4-layer architecture with ESLint-enforced layer boundaries.
Codebase: 7 plugin submodules + 1 boiler-template, TypeScript under src/.
Tech Stack
| Component | Technology |
|---|
| Language | TypeScript (strict mode, ES modules) |
| Runtime | Node.js via Obsidian's Electron |
| UI Framework | Obsidian API (Views, Modals, Settings) |
| Build | esbuild (esbuild.config.mjs) |
| Package Manager | pnpm (workspace) |
| Linter | ESLint flat config (eslint.config.mts) |
| Commit Lint | commitlint + Husky hooks |
| Release | Automated via scripts/release.mjs |
| CI/CD | GitHub Actions (generated by boiler-template) |
| Template Sync | Custom sync engine (tooling/sync/index.mjs) |
Architecture
Directory Map (per plugin src/)
| Directory | Purpose | obsidian import? |
|---|
main.ts | Composition root โ wires everything | Yes |
domain/ | Business logic, pure functions | No |
ui/ | Views, modals, settings, commands, adapters with I/O | Yes |
types/ | Pure type definitions | No |
utils/ | Pure functions, zero state | No |
shared/ | Boiler-template synced modules | Yes |
Dependency Direction
utils/ โโโ
types/ โโโผโโ domain/ โโ ui/ โโ main.ts
shared/ โโ โ
โโโ shared/
Monorepo Layout
| Submodule | Purpose | Default Branch |
|---|
obsidian-eagle-plugin | Image upload to Eagle app | main |
open-connections | Semantic note connections via embeddings | main |
Metadata-Auto-Classifier | AI-powered metadata classification | master |
obsidian-boiler-template | Source-of-truth seed template | master |
obsidian-bible-search | Bible verse search (private) | main |
obsidian-qmd | QMD semantic search integration | main |
youtube-note-playlist | YouTube music player via yt-dlp | main |
Key Files (per plugin)
| File | Role |
|---|
src/main.ts | Plugin entry point, onload() / onunload() |
src/ui/settings*.ts | Plugin settings tab |
src/shared/plugin-logger.ts | Structured logger (synced) |
src/shared/plugin-notices.ts | Catalog-driven notice system (synced) |
src/shared/settings-migration.ts | Settings version migration (synced) |
boiler.config.mjs | Per-plugin sync overrides |
eslint.config.mts | ESLint config (synced from boiler-template) |
Boiler-Template Key Files
| File | Role |
|---|
tooling/sync/index.mjs | Sync engine core |
tooling/sync/targets.json | Managed plugin list |
scripts/release.mjs | Release pipeline (CI -> version bump -> tag) |
scripts/sync-to-plugins.mjs | CLI for sync operations |
tooling/shared/ | Shared source modules, scripts, infra |
Patterns & Conventions
Plugin Entry Point
Every plugin extends Plugin and uses onload() as the composition root:
import { Plugin } from 'obsidian';
export default class MyPlugin extends Plugin {
async onload() {
this.addCommand({ ... });
this.registerView(VIEW_TYPE, (leaf) => new MyView(leaf));
this.addSettingTab(new MySettingTab(this.app, this));
this.registerEvent(this.app.vault.on('modify', handler));
}
onunload() { }
}
Layer Boundary Enforcement
ESLint no-restricted-imports prevents domain/, types/, and utils/ from importing obsidian. Verified with:
rg "import.*from 'obsidian'" */src/domain/
Obsidian Types in Domain Code
Define shim interfaces in types/ instead of importing from obsidian:
export interface FileRef { path: string; }
export interface NoteMetadata { frontmatter?: Record<string, unknown>; }
main.ts passes real Obsidian objects which satisfy these via structural typing.
Shared Module Pattern
Modules in src/shared/ are synced from boiler-template. Never edit directly in downstream plugins โ change in boiler-template, then propagate.
Naming Conventions
| Element | Convention | Example |
|---|
| Files | kebab-case | qmd-process-adapter.ts, query-builder.ts |
| Classes | PascalCase | QmdProcessAdapter, EmbedStore |
| Types/Interfaces | PascalCase | FileRef, EmbedState, PluginSettings |
| Constants | SCREAMING_SNAKE_CASE | CACHE_MAX_SIZE, DEFAULT_DELAY_MS |
| Functions | camelCase | parseCollectionList, sanitizeForVec |
| Directories | kebab-case | domain/, ui/, shared/ |
Available Skills
| Skill | Trigger | Purpose |
|---|
obsidian-propagate | "sync", "propagate", "push template changes" | Sync boiler-template to downstream plugins |
obsidian-runtime-debug | Runtime errors, plugin state reset, profiling | Debug plugins in live vault with obsidian-cli |
frontend-design | Build web components, UI design | Production-grade frontend interfaces |
Agent Team
| Agent | Role | Owns |
|---|
obsidian-developer | Implementation โ domain logic, infrastructure | main.ts, domain/, types/, utils/, shared/, test/ |
obsidian-ui | UX design + visual implementation | ui/settings*, ui/connections/, ui/views/, styles.css |
obsidian-qa | Runtime verification + static code review | All files (read), fixes where needed |
Mandatory Rules
- index.ts is an entry point โ re-exports and wiring only, no business logic
- No catch-all files โ
utils.ts, helpers.ts, service.ts are banned
- Single Responsibility โ one file = one responsibility
- 200 LOC hard limit โ files exceeding this must be split
Release Workflow
pnpm run ci
pnpm release:patch|minor|major
git tag, git push --tags, gh release, npm publish are DENIED by settings.json.
Configuration
| Setting | Location |
|---|
| Plugin settings | <vault>/.obsidian/plugins/<id>/data.json |
| Claude Code permissions | .claude/settings.json |
| Agent definitions | .claude/agents/*.md |
| Skill definitions | .claude/skills/*/SKILL.md |
| ESLint config | eslint.config.mts (synced) |
| Per-plugin sync | boiler.config.mjs |
| Sync targets | obsidian-boiler-template/tooling/sync/targets.json |
Documentation
Detailed guides in docs/:
| Guide | Purpose |
|---|
| Architecture | Layer structure, dependency rules, data flow |
| Exploration Guide | Study paths, grep patterns, feature-to-file mapping |
| Rules | Mandatory code rules with enforcement grep commands |
| Patterns | 8 proven patterns with code examples |
| Gotchas | 7 known pitfalls with fixes |
| Obsidian API | API quirks and workarounds |
| Collaboration | Agent roles, handoff protocol, Definition of Done |
Guidelines
- Read relevant source files before making changes โ understand existing patterns first.
- Follow the 4-layer architecture. If it needs
obsidian, it belongs in ui/.
- Keep edits minimal and focused โ avoid unnecessary refactoring.
- Never edit
src/shared/ in downstream plugins โ change in boiler-template, then propagate.
- Always dry-run before syncing:
node scripts/sync-to-plugins.mjs --dry-run.
- Run
pnpm run ci before declaring work complete.
- Respect the branch strategy โ never commit directly to main/master.
- Update
docs/ as project conventions evolve.