Various AT Protocol integrations with obsidian
at main 251 lines 9.9 kB view raw view rendered
1# Obsidian community plugin 2 3## Project overview 4 5- Target: Obsidian Community Plugin (TypeScript → bundled JavaScript). 6- Entry point: `main.ts` compiled to `main.js` and loaded by Obsidian. 7- Required release artifacts: `main.js`, `manifest.json`, and optional `styles.css`. 8 9## Environment & tooling 10 11- Node.js: use current LTS (Node 18+ recommended). 12- **Package manager: npm** (required for this sample - `package.json` defines npm scripts and dependencies). 13- **Bundler: esbuild** (required for this sample - `esbuild.config.mjs` and build scripts depend on it). Alternative bundlers like Rollup or webpack are acceptable for other projects if they bundle all external dependencies into `main.js`. 14- Types: `obsidian` type definitions. 15 16**Note**: This sample project has specific technical dependencies on npm and esbuild. If you're creating a plugin from scratch, you can choose different tools, but you'll need to replace the build configuration accordingly. 17 18### Install 19 20```bash 21npm install 22``` 23 24### Dev (watch) 25 26```bash 27npm run dev 28``` 29 30### Production build 31 32```bash 33npm run build 34``` 35 36## Linting 37 38- To use eslint install eslint from terminal: `npm install -g eslint` 39- To use eslint to analyze this project use this command: `eslint main.ts` 40- eslint will then create a report with suggestions for code improvement by file and line number. 41- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder: `eslint ./src/` 42 43## File & folder conventions 44 45- **Organize code into multiple files**: Split functionality across separate modules rather than putting everything in `main.ts`. 46- Source lives in `src/`. Keep `main.ts` small and focused on plugin lifecycle (loading, unloading, registering commands). 47- **Example file structure**: 48 ``` 49 src/ 50 main.ts # Plugin entry point, lifecycle management 51 settings.ts # Settings interface and defaults 52 commands/ # Command implementations 53 command1.ts 54 command2.ts 55 ui/ # UI components, modals, views 56 modal.ts 57 view.ts 58 utils/ # Utility functions, helpers 59 helpers.ts 60 constants.ts 61 types.ts # TypeScript interfaces and types 62 ``` 63- **Do not commit build artifacts**: Never commit `node_modules/`, `main.js`, or other generated files to version control. 64- Keep the plugin small. Avoid large dependencies. Prefer browser-compatible packages. 65- Generated output should be placed at the plugin root or `dist/` depending on your build setup. Release artifacts must end up at the top level of the plugin folder in the vault (`main.js`, `manifest.json`, `styles.css`). 66 67## Manifest rules (`manifest.json`) 68 69- Must include (non-exhaustive): 70 - `id` (plugin ID; for local dev it should match the folder name) 71 - `name` 72 - `version` (Semantic Versioning `x.y.z`) 73 - `minAppVersion` 74 - `description` 75 - `isDesktopOnly` (boolean) 76 - Optional: `author`, `authorUrl`, `fundingUrl` (string or map) 77- Never change `id` after release. Treat it as stable API. 78- Keep `minAppVersion` accurate when using newer APIs. 79- Canonical requirements are coded here: https://github.com/obsidianmd/obsidian-releases/blob/master/.github/workflows/validate-plugin-entry.yml 80 81## Testing 82 83- Manual install for testing: copy `main.js`, `manifest.json`, `styles.css` (if any) to: 84 ``` 85 <Vault>/.obsidian/plugins/<plugin-id>/ 86 ``` 87- Reload Obsidian and enable the plugin in **Settings → Community plugins**. 88 89## Commands & settings 90 91- Any user-facing commands should be added via `this.addCommand(...)`. 92- If the plugin has configuration, provide a settings tab and sensible defaults. 93- Persist settings using `this.loadData()` / `this.saveData()`. 94- Use stable command IDs; avoid renaming once released. 95 96## Versioning & releases 97 98- Bump `version` in `manifest.json` (SemVer) and update `versions.json` to map plugin version → minimum app version. 99- Create a GitHub release whose tag exactly matches `manifest.json`'s `version`. Do not use a leading `v`. 100- Attach `manifest.json`, `main.js`, and `styles.css` (if present) to the release as individual assets. 101- After the initial release, follow the process to add/update your plugin in the community catalog as required. 102 103## Security, privacy, and compliance 104 105Follow Obsidian's **Developer Policies** and **Plugin Guidelines**. In particular: 106 107- Default to local/offline operation. Only make network requests when essential to the feature. 108- No hidden telemetry. If you collect optional analytics or call third-party services, require explicit opt-in and document clearly in `README.md` and in settings. 109- Never execute remote code, fetch and eval scripts, or auto-update plugin code outside of normal releases. 110- Minimize scope: read/write only what's necessary inside the vault. Do not access files outside the vault. 111- Clearly disclose any external services used, data sent, and risks. 112- Respect user privacy. Do not collect vault contents, filenames, or personal information unless absolutely necessary and explicitly consented. 113- Avoid deceptive patterns, ads, or spammy notifications. 114- Register and clean up all DOM, app, and interval listeners using the provided `register*` helpers so the plugin unloads safely. 115 116## UX & copy guidelines (for UI text, commands, settings) 117 118- Prefer sentence case for headings, buttons, and titles. 119- Use clear, action-oriented imperatives in step-by-step copy. 120- Use **bold** to indicate literal UI labels. Prefer "select" for interactions. 121- Use arrow notation for navigation: **Settings → Community plugins**. 122- Keep in-app strings short, consistent, and free of jargon. 123 124## Performance 125 126- Keep startup light. Defer heavy work until needed. 127- Avoid long-running tasks during `onload`; use lazy initialization. 128- Batch disk access and avoid excessive vault scans. 129- Debounce/throttle expensive operations in response to file system events. 130 131## Coding conventions 132 133- TypeScript with `"strict": true` preferred. 134- **Keep `main.ts` minimal**: Focus only on plugin lifecycle (onload, onunload, addCommand calls). Delegate all feature logic to separate modules. 135- **Split large files**: If any file exceeds ~200-300 lines, consider breaking it into smaller, focused modules. 136- **Use clear module boundaries**: Each file should have a single, well-defined responsibility. 137- Bundle everything into `main.js` (no unbundled runtime deps). 138- Avoid Node/Electron APIs if you want mobile compatibility; set `isDesktopOnly` accordingly. 139- Prefer `async/await` over promise chains; handle errors gracefully. 140 141## Mobile 142 143- Where feasible, test on iOS and Android. 144- Don't assume desktop-only behavior unless `isDesktopOnly` is `true`. 145- Avoid large in-memory structures; be mindful of memory and storage constraints. 146 147## Agent do/don't 148 149**Do** 150- Add commands with stable IDs (don't rename once released). 151- Provide defaults and validation in settings. 152- Write idempotent code paths so reload/unload doesn't leak listeners or intervals. 153- Use `this.register*` helpers for everything that needs cleanup. 154 155**Don't** 156- Introduce network calls without an obvious user-facing reason and documentation. 157- Ship features that require cloud services without clear disclosure and explicit opt-in. 158- Store or transmit vault contents unless essential and consented. 159 160## Common tasks 161 162### Organize code across multiple files 163 164**main.ts** (minimal, lifecycle only): 165```ts 166import { Plugin } from "obsidian"; 167import { MySettings, DEFAULT_SETTINGS } from "./settings"; 168import { registerCommands } from "./commands"; 169 170export default class MyPlugin extends Plugin { 171 settings: MySettings; 172 173 async onload() { 174 this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 175 registerCommands(this); 176 } 177} 178``` 179 180**settings.ts**: 181```ts 182export interface MySettings { 183 enabled: boolean; 184 apiKey: string; 185} 186 187export const DEFAULT_SETTINGS: MySettings = { 188 enabled: true, 189 apiKey: "", 190}; 191``` 192 193**commands/index.ts**: 194```ts 195import { Plugin } from "obsidian"; 196import { doSomething } from "./my-command"; 197 198export function registerCommands(plugin: Plugin) { 199 plugin.addCommand({ 200 id: "do-something", 201 name: "Do something", 202 callback: () => doSomething(plugin), 203 }); 204} 205``` 206 207### Add a command 208 209```ts 210this.addCommand({ 211 id: "your-command-id", 212 name: "Do the thing", 213 callback: () => this.doTheThing(), 214}); 215``` 216 217### Persist settings 218 219```ts 220interface MySettings { enabled: boolean } 221const DEFAULT_SETTINGS: MySettings = { enabled: true }; 222 223async onload() { 224 this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 225 await this.saveData(this.settings); 226} 227``` 228 229### Register listeners safely 230 231```ts 232this.registerEvent(this.app.workspace.on("file-open", f => { /* ... */ })); 233this.registerDomEvent(window, "resize", () => { /* ... */ }); 234this.registerInterval(window.setInterval(() => { /* ... */ }, 1000)); 235``` 236 237## Troubleshooting 238 239- Plugin doesn't load after build: ensure `main.js` and `manifest.json` are at the top level of the plugin folder under `<Vault>/.obsidian/plugins/<plugin-id>/`. 240- Build issues: if `main.js` is missing, run `npm run build` or `npm run dev` to compile your TypeScript source code. 241- Commands not appearing: verify `addCommand` runs after `onload` and IDs are unique. 242- Settings not persisting: ensure `loadData`/`saveData` are awaited and you re-render the UI after changes. 243- Mobile-only issues: confirm you're not using desktop-only APIs; check `isDesktopOnly` and adjust. 244 245## References 246 247- Obsidian sample plugin: https://github.com/obsidianmd/obsidian-sample-plugin 248- API documentation: https://docs.obsidian.md 249- Developer policies: https://docs.obsidian.md/Developer+policies 250- Plugin guidelines: https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines 251- Style guide: https://help.obsidian.md/style-guide