Skip to content

Commit db97f5f

Browse files
authored
Merge pull request #155 from obsidianmd/agents-md
AGENTS.md
2 parents 6d09ce3 + 9673533 commit db97f5f

File tree

2 files changed

+252
-1
lines changed

2 files changed

+252
-1
lines changed

AGENTS.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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
21+
npm install
22+
```
23+
24+
### Dev (watch)
25+
26+
```bash
27+
npm run dev
28+
```
29+
30+
### Production build
31+
32+
```bash
33+
npm 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+
105+
Follow 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
166+
import { Plugin } from "obsidian";
167+
import { MySettings, DEFAULT_SETTINGS } from "./settings";
168+
import { registerCommands } from "./commands";
169+
170+
export 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
182+
export interface MySettings {
183+
enabled: boolean;
184+
apiKey: string;
185+
}
186+
187+
export const DEFAULT_SETTINGS: MySettings = {
188+
enabled: true,
189+
apiKey: "",
190+
};
191+
```
192+
193+
**commands/index.ts**:
194+
```ts
195+
import { Plugin } from "obsidian";
196+
import { doSomething } from "./my-command";
197+
198+
export 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
210+
this.addCommand({
211+
id: "your-command-id",
212+
name: "Do the thing",
213+
callback: () => this.doTheThing(),
214+
});
215+
```
216+
217+
### Persist settings
218+
219+
```ts
220+
interface MySettings { enabled: boolean }
221+
const DEFAULT_SETTINGS: MySettings = { enabled: true };
222+
223+
async 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
232+
this.registerEvent(this.app.workspace.on("file-open", f => { /* ... */ }));
233+
this.registerDomEvent(window, "resize", () => { /* ... */ });
234+
this.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

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Quick starting guide for new plugin devs:
6363
- `eslint main.ts`
6464
- eslint will then create a report with suggestions for code improvement by file and line number.
6565
- 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:
66-
- `eslint .\src\`
66+
- `eslint ./src/`
6767

6868
## Funding URL
6969

0 commit comments

Comments
 (0)