Various AT Protocol integrations with obsidian
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