@jayjiang/byoao 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/cli/cli-program.js +241 -0
  2. package/dist/cli/cli-program.js.map +1 -0
  3. package/dist/cli/installer.js +226 -0
  4. package/dist/cli/installer.js.map +1 -0
  5. package/dist/cli/ui.js +157 -0
  6. package/dist/cli/ui.js.map +1 -0
  7. package/dist/hooks/idle-suggestions.js +14 -0
  8. package/dist/hooks/idle-suggestions.js.map +1 -0
  9. package/dist/hooks/system-transform.js +34 -0
  10. package/dist/hooks/system-transform.js.map +1 -0
  11. package/dist/index.js +43 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/plugin-config.js +57 -0
  14. package/dist/plugin-config.js.map +1 -0
  15. package/dist/tools/add-glossary-term.js +19 -0
  16. package/dist/tools/add-glossary-term.js.map +1 -0
  17. package/dist/tools/add-member.js +21 -0
  18. package/dist/tools/add-member.js.map +1 -0
  19. package/dist/tools/add-project.js +24 -0
  20. package/dist/tools/add-project.js.map +1 -0
  21. package/dist/tools/init-vault.js +82 -0
  22. package/dist/tools/init-vault.js.map +1 -0
  23. package/dist/tools/vault-doctor.js +38 -0
  24. package/dist/tools/vault-doctor.js.map +1 -0
  25. package/dist/tools/vault-status.js +18 -0
  26. package/dist/tools/vault-status.js.map +1 -0
  27. package/dist/vault/create.js +230 -0
  28. package/dist/vault/create.js.map +1 -0
  29. package/dist/vault/doctor.js +148 -0
  30. package/dist/vault/doctor.js.map +1 -0
  31. package/dist/vault/glossary.js +33 -0
  32. package/dist/vault/glossary.js.map +1 -0
  33. package/dist/vault/member.js +67 -0
  34. package/dist/vault/member.js.map +1 -0
  35. package/dist/vault/obsidian-check.js +125 -0
  36. package/dist/vault/obsidian-check.js.map +1 -0
  37. package/dist/vault/obsidian-cli.js +47 -0
  38. package/dist/vault/obsidian-cli.js.map +1 -0
  39. package/dist/vault/opencode-check.js +65 -0
  40. package/dist/vault/opencode-check.js.map +1 -0
  41. package/dist/vault/preset.js +48 -0
  42. package/dist/vault/preset.js.map +1 -0
  43. package/dist/vault/project.js +68 -0
  44. package/dist/vault/project.js.map +1 -0
  45. package/dist/vault/status.js +135 -0
  46. package/dist/vault/status.js.map +1 -0
  47. package/dist/vault/template.js +14 -0
  48. package/dist/vault/template.js.map +1 -0
  49. package/package.json +58 -0
  50. package/src/assets/obsidian-skills/defuddle.md +41 -0
  51. package/src/assets/obsidian-skills/json-canvas.md +244 -0
  52. package/src/assets/obsidian-skills/obsidian-bases.md +497 -0
  53. package/src/assets/obsidian-skills/obsidian-cli.md +106 -0
  54. package/src/assets/obsidian-skills/obsidian-markdown.md +196 -0
  55. package/src/assets/presets/common/AGENT.md.hbs +29 -0
  56. package/src/assets/presets/common/Glossary.md.hbs +44 -0
  57. package/src/assets/presets/common/Start Here.md.hbs +95 -0
  58. package/src/assets/presets/common/obsidian/core-plugins.json +33 -0
  59. package/src/assets/presets/common/obsidian/daily-notes.json +5 -0
  60. package/src/assets/presets/common/obsidian/templates.json +3 -0
  61. package/src/assets/presets/common/templates/Daily Note.md +19 -0
  62. package/src/assets/presets/common/templates/Decision Record.md +32 -0
  63. package/src/assets/presets/common/templates/Investigation.md +34 -0
  64. package/src/assets/presets/common/templates/Meeting Notes.md +25 -0
  65. package/src/assets/presets/pm-tpm/agent-section.hbs +15 -0
  66. package/src/assets/presets/pm-tpm/preset.json +12 -0
  67. package/src/assets/presets/pm-tpm/templates/Feature Doc.md +45 -0
  68. package/src/assets/presets/pm-tpm/templates/Sprint Handoff.md +38 -0
  69. package/src/assets/web-clipper/confluence-page.json +63 -0
  70. package/src/assets/web-clipper/general-article.json +53 -0
  71. package/src/assets/web-clipper/jira-issue.json +68 -0
  72. package/src/assets/web-clipper/meeting-notes.json +53 -0
  73. package/src/skills/enrich-document.md +52 -0
  74. package/src/skills/init-knowledge-base.md +85 -0
  75. package/src/skills/system-explainer.md +58 -0
  76. package/src/skills/vault-doctor.md +73 -0
@@ -0,0 +1,497 @@
1
+ ---
2
+ name: obsidian-bases
3
+ description: Create and edit Obsidian Bases (.base files) with views, filters, formulas, and summaries. Use when working with .base files, creating database-like views of notes, or when the user mentions Bases, table views, card views, filters, or formulas in Obsidian.
4
+ ---
5
+
6
+ # Obsidian Bases Skill
7
+
8
+ ## Workflow
9
+
10
+ 1. **Create the file**: Create a `.base` file in the vault with valid YAML content
11
+ 2. **Define scope**: Add `filters` to select which notes appear (by tag, folder, property, or date)
12
+ 3. **Add formulas** (optional): Define computed properties in the `formulas` section
13
+ 4. **Configure views**: Add one or more views (`table`, `cards`, `list`, or `map`) with `order` specifying which properties to display
14
+ 5. **Validate**: Verify the file is valid YAML with no syntax errors. Check that all referenced properties and formulas exist. Common issues: unquoted strings containing special YAML characters, mismatched quotes in formula expressions, referencing `formula.X` without defining `X` in `formulas`
15
+ 6. **Test in Obsidian**: Open the `.base` file in Obsidian to confirm the view renders correctly. If it shows a YAML error, check quoting rules below
16
+
17
+ ## Schema
18
+
19
+ Base files use the `.base` extension and contain valid YAML.
20
+
21
+ ```yaml
22
+ # Global filters apply to ALL views in the base
23
+ filters:
24
+ # Can be a single filter string
25
+ # OR a recursive filter object with and/or/not
26
+ and: []
27
+ or: []
28
+ not: []
29
+
30
+ # Define formula properties that can be used across all views
31
+ formulas:
32
+ formula_name: 'expression'
33
+
34
+ # Configure display names and settings for properties
35
+ properties:
36
+ property_name:
37
+ displayName: "Display Name"
38
+ formula.formula_name:
39
+ displayName: "Formula Display Name"
40
+ file.ext:
41
+ displayName: "Extension"
42
+
43
+ # Define custom summary formulas
44
+ summaries:
45
+ custom_summary_name: 'values.mean().round(3)'
46
+
47
+ # Define one or more views
48
+ views:
49
+ - type: table | cards | list | map
50
+ name: "View Name"
51
+ limit: 10 # Optional: limit results
52
+ groupBy: # Optional: group results
53
+ property: property_name
54
+ direction: ASC | DESC
55
+ filters: # View-specific filters
56
+ and: []
57
+ order: # Properties to display in order
58
+ - file.name
59
+ - property_name
60
+ - formula.formula_name
61
+ summaries: # Map properties to summary formulas
62
+ property_name: Average
63
+ ```
64
+
65
+ ## Filter Syntax
66
+
67
+ Filters narrow down results. They can be applied globally or per-view.
68
+
69
+ ### Filter Structure
70
+
71
+ ```yaml
72
+ # Single filter
73
+ filters: 'status == "done"'
74
+
75
+ # AND - all conditions must be true
76
+ filters:
77
+ and:
78
+ - 'status == "done"'
79
+ - 'priority > 3'
80
+
81
+ # OR - any condition can be true
82
+ filters:
83
+ or:
84
+ - 'file.hasTag("book")'
85
+ - 'file.hasTag("article")'
86
+
87
+ # NOT - exclude matching items
88
+ filters:
89
+ not:
90
+ - 'file.hasTag("archived")'
91
+
92
+ # Nested filters
93
+ filters:
94
+ or:
95
+ - file.hasTag("tag")
96
+ - and:
97
+ - file.hasTag("book")
98
+ - file.hasLink("Textbook")
99
+ - not:
100
+ - file.hasTag("book")
101
+ - file.inFolder("Required Reading")
102
+ ```
103
+
104
+ ### Filter Operators
105
+
106
+ | Operator | Description |
107
+ |----------|-------------|
108
+ | `==` | equals |
109
+ | `!=` | not equal |
110
+ | `>` | greater than |
111
+ | `<` | less than |
112
+ | `>=` | greater than or equal |
113
+ | `<=` | less than or equal |
114
+ | `&&` | logical and |
115
+ | `\|\|` | logical or |
116
+ | `!` | logical not |
117
+
118
+ ## Properties
119
+
120
+ ### Three Types of Properties
121
+
122
+ 1. **Note properties** - From frontmatter: `note.author` or just `author`
123
+ 2. **File properties** - File metadata: `file.name`, `file.mtime`, etc.
124
+ 3. **Formula properties** - Computed values: `formula.my_formula`
125
+
126
+ ### File Properties Reference
127
+
128
+ | Property | Type | Description |
129
+ |----------|------|-------------|
130
+ | `file.name` | String | File name |
131
+ | `file.basename` | String | File name without extension |
132
+ | `file.path` | String | Full path to file |
133
+ | `file.folder` | String | Parent folder path |
134
+ | `file.ext` | String | File extension |
135
+ | `file.size` | Number | File size in bytes |
136
+ | `file.ctime` | Date | Created time |
137
+ | `file.mtime` | Date | Modified time |
138
+ | `file.tags` | List | All tags in file |
139
+ | `file.links` | List | Internal links in file |
140
+ | `file.backlinks` | List | Files linking to this file |
141
+ | `file.embeds` | List | Embeds in the note |
142
+ | `file.properties` | Object | All frontmatter properties |
143
+
144
+ ### The `this` Keyword
145
+
146
+ - In main content area: refers to the base file itself
147
+ - When embedded: refers to the embedding file
148
+ - In sidebar: refers to the active file in main content
149
+
150
+ ## Formula Syntax
151
+
152
+ Formulas compute values from properties. Defined in the `formulas` section.
153
+
154
+ ```yaml
155
+ formulas:
156
+ # Simple arithmetic
157
+ total: "price * quantity"
158
+
159
+ # Conditional logic
160
+ status_icon: 'if(done, "✅", "⏳")'
161
+
162
+ # String formatting
163
+ formatted_price: 'if(price, price.toFixed(2) + " dollars")'
164
+
165
+ # Date formatting
166
+ created: 'file.ctime.format("YYYY-MM-DD")'
167
+
168
+ # Calculate days since created (use .days for Duration)
169
+ days_old: '(now() - file.ctime).days'
170
+
171
+ # Calculate days until due date
172
+ days_until_due: 'if(due_date, (date(due_date) - today()).days, "")'
173
+ ```
174
+
175
+ ## Key Functions
176
+
177
+ Most commonly used functions. For the complete reference of all types (Date, String, Number, List, File, Link, Object, RegExp), see [FUNCTIONS_REFERENCE.md](references/FUNCTIONS_REFERENCE.md).
178
+
179
+ | Function | Signature | Description |
180
+ |----------|-----------|-------------|
181
+ | `date()` | `date(string): date` | Parse string to date (`YYYY-MM-DD HH:mm:ss`) |
182
+ | `now()` | `now(): date` | Current date and time |
183
+ | `today()` | `today(): date` | Current date (time = 00:00:00) |
184
+ | `if()` | `if(condition, trueResult, falseResult?)` | Conditional |
185
+ | `duration()` | `duration(string): duration` | Parse duration string |
186
+ | `file()` | `file(path): file` | Get file object |
187
+ | `link()` | `link(path, display?): Link` | Create a link |
188
+
189
+ ### Duration Type
190
+
191
+ When subtracting two dates, the result is a **Duration** type (not a number).
192
+
193
+ **Duration Fields:** `duration.days`, `duration.hours`, `duration.minutes`, `duration.seconds`, `duration.milliseconds`
194
+
195
+ **IMPORTANT:** Duration does NOT support `.round()`, `.floor()`, `.ceil()` directly. Access a numeric field first (like `.days`), then apply number functions.
196
+
197
+ ```yaml
198
+ # CORRECT: Calculate days between dates
199
+ "(date(due_date) - today()).days" # Returns number of days
200
+ "(now() - file.ctime).days" # Days since created
201
+ "(date(due_date) - today()).days.round(0)" # Rounded days
202
+
203
+ # WRONG - will cause error:
204
+ # "((date(due) - today()) / 86400000).round(0)" # Duration doesn't support division then round
205
+ ```
206
+
207
+ ### Date Arithmetic
208
+
209
+ ```yaml
210
+ # Duration units: y/year/years, M/month/months, d/day/days,
211
+ # w/week/weeks, h/hour/hours, m/minute/minutes, s/second/seconds
212
+ "now() + \"1 day\"" # Tomorrow
213
+ "today() + \"7d\"" # A week from today
214
+ "now() - file.ctime" # Returns Duration
215
+ "(now() - file.ctime).days" # Get days as number
216
+ ```
217
+
218
+ ## View Types
219
+
220
+ ### Table View
221
+
222
+ ```yaml
223
+ views:
224
+ - type: table
225
+ name: "My Table"
226
+ order:
227
+ - file.name
228
+ - status
229
+ - due_date
230
+ summaries:
231
+ price: Sum
232
+ count: Average
233
+ ```
234
+
235
+ ### Cards View
236
+
237
+ ```yaml
238
+ views:
239
+ - type: cards
240
+ name: "Gallery"
241
+ order:
242
+ - file.name
243
+ - cover_image
244
+ - description
245
+ ```
246
+
247
+ ### List View
248
+
249
+ ```yaml
250
+ views:
251
+ - type: list
252
+ name: "Simple List"
253
+ order:
254
+ - file.name
255
+ - status
256
+ ```
257
+
258
+ ### Map View
259
+
260
+ Requires latitude/longitude properties and the Maps community plugin.
261
+
262
+ ```yaml
263
+ views:
264
+ - type: map
265
+ name: "Locations"
266
+ # Map-specific settings for lat/lng properties
267
+ ```
268
+
269
+ ## Default Summary Formulas
270
+
271
+ | Name | Input Type | Description |
272
+ |------|------------|-------------|
273
+ | `Average` | Number | Mathematical mean |
274
+ | `Min` | Number | Smallest number |
275
+ | `Max` | Number | Largest number |
276
+ | `Sum` | Number | Sum of all numbers |
277
+ | `Range` | Number | Max - Min |
278
+ | `Median` | Number | Mathematical median |
279
+ | `Stddev` | Number | Standard deviation |
280
+ | `Earliest` | Date | Earliest date |
281
+ | `Latest` | Date | Latest date |
282
+ | `Range` | Date | Latest - Earliest |
283
+ | `Checked` | Boolean | Count of true values |
284
+ | `Unchecked` | Boolean | Count of false values |
285
+ | `Empty` | Any | Count of empty values |
286
+ | `Filled` | Any | Count of non-empty values |
287
+ | `Unique` | Any | Count of unique values |
288
+
289
+ ## Complete Examples
290
+
291
+ ### Task Tracker Base
292
+
293
+ ```yaml
294
+ filters:
295
+ and:
296
+ - file.hasTag("task")
297
+ - 'file.ext == "md"'
298
+
299
+ formulas:
300
+ days_until_due: 'if(due, (date(due) - today()).days, "")'
301
+ is_overdue: 'if(due, date(due) < today() && status != "done", false)'
302
+ priority_label: 'if(priority == 1, "🔴 High", if(priority == 2, "🟡 Medium", "🟢 Low"))'
303
+
304
+ properties:
305
+ status:
306
+ displayName: Status
307
+ formula.days_until_due:
308
+ displayName: "Days Until Due"
309
+ formula.priority_label:
310
+ displayName: Priority
311
+
312
+ views:
313
+ - type: table
314
+ name: "Active Tasks"
315
+ filters:
316
+ and:
317
+ - 'status != "done"'
318
+ order:
319
+ - file.name
320
+ - status
321
+ - formula.priority_label
322
+ - due
323
+ - formula.days_until_due
324
+ groupBy:
325
+ property: status
326
+ direction: ASC
327
+ summaries:
328
+ formula.days_until_due: Average
329
+
330
+ - type: table
331
+ name: "Completed"
332
+ filters:
333
+ and:
334
+ - 'status == "done"'
335
+ order:
336
+ - file.name
337
+ - completed_date
338
+ ```
339
+
340
+ ### Reading List Base
341
+
342
+ ```yaml
343
+ filters:
344
+ or:
345
+ - file.hasTag("book")
346
+ - file.hasTag("article")
347
+
348
+ formulas:
349
+ reading_time: 'if(pages, (pages * 2).toString() + " min", "")'
350
+ status_icon: 'if(status == "reading", "📖", if(status == "done", "✅", "📚"))'
351
+ year_read: 'if(finished_date, date(finished_date).year, "")'
352
+
353
+ properties:
354
+ author:
355
+ displayName: Author
356
+ formula.status_icon:
357
+ displayName: ""
358
+ formula.reading_time:
359
+ displayName: "Est. Time"
360
+
361
+ views:
362
+ - type: cards
363
+ name: "Library"
364
+ order:
365
+ - cover
366
+ - file.name
367
+ - author
368
+ - formula.status_icon
369
+ filters:
370
+ not:
371
+ - 'status == "dropped"'
372
+
373
+ - type: table
374
+ name: "Reading List"
375
+ filters:
376
+ and:
377
+ - 'status == "to-read"'
378
+ order:
379
+ - file.name
380
+ - author
381
+ - pages
382
+ - formula.reading_time
383
+ ```
384
+
385
+ ### Daily Notes Index
386
+
387
+ ```yaml
388
+ filters:
389
+ and:
390
+ - file.inFolder("Daily Notes")
391
+ - '/^\d{4}-\d{2}-\d{2}$/.matches(file.basename)'
392
+
393
+ formulas:
394
+ word_estimate: '(file.size / 5).round(0)'
395
+ day_of_week: 'date(file.basename).format("dddd")'
396
+
397
+ properties:
398
+ formula.day_of_week:
399
+ displayName: "Day"
400
+ formula.word_estimate:
401
+ displayName: "~Words"
402
+
403
+ views:
404
+ - type: table
405
+ name: "Recent Notes"
406
+ limit: 30
407
+ order:
408
+ - file.name
409
+ - formula.day_of_week
410
+ - formula.word_estimate
411
+ - file.mtime
412
+ ```
413
+
414
+ ## Embedding Bases
415
+
416
+ Embed in Markdown files:
417
+
418
+ ```markdown
419
+ ![[MyBase.base]]
420
+
421
+ <!-- Specific view -->
422
+ ![[MyBase.base#View Name]]
423
+ ```
424
+
425
+ ## YAML Quoting Rules
426
+
427
+ - Use single quotes for formulas containing double quotes: `'if(done, "Yes", "No")'`
428
+ - Use double quotes for simple strings: `"My View Name"`
429
+ - Escape nested quotes properly in complex expressions
430
+
431
+ ## Troubleshooting
432
+
433
+ ### YAML Syntax Errors
434
+
435
+ **Unquoted special characters**: Strings containing `:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` `` must be quoted.
436
+
437
+ ```yaml
438
+ # WRONG - colon in unquoted string
439
+ displayName: Status: Active
440
+
441
+ # CORRECT
442
+ displayName: "Status: Active"
443
+ ```
444
+
445
+ **Mismatched quotes in formulas**: When a formula contains double quotes, wrap the entire formula in single quotes.
446
+
447
+ ```yaml
448
+ # WRONG - double quotes inside double quotes
449
+ formulas:
450
+ label: "if(done, "Yes", "No")"
451
+
452
+ # CORRECT - single quotes wrapping double quotes
453
+ formulas:
454
+ label: 'if(done, "Yes", "No")'
455
+ ```
456
+
457
+ ### Common Formula Errors
458
+
459
+ **Duration math without field access**: Subtracting dates returns a Duration, not a number. Always access `.days`, `.hours`, etc.
460
+
461
+ ```yaml
462
+ # WRONG - Duration is not a number
463
+ "(now() - file.ctime).round(0)"
464
+
465
+ # CORRECT - access .days first, then round
466
+ "(now() - file.ctime).days.round(0)"
467
+ ```
468
+
469
+ **Missing null checks**: Properties may not exist on all notes. Use `if()` to guard.
470
+
471
+ ```yaml
472
+ # WRONG - crashes if due_date is empty
473
+ "(date(due_date) - today()).days"
474
+
475
+ # CORRECT - guard with if()
476
+ 'if(due_date, (date(due_date) - today()).days, "")'
477
+ ```
478
+
479
+ **Referencing undefined formulas**: Ensure every `formula.X` in `order` or `properties` has a matching entry in `formulas`.
480
+
481
+ ```yaml
482
+ # This will fail silently if 'total' is not defined in formulas
483
+ order:
484
+ - formula.total
485
+
486
+ # Fix: define it
487
+ formulas:
488
+ total: "price * quantity"
489
+ ```
490
+
491
+ ## References
492
+
493
+ - [Bases Syntax](https://help.obsidian.md/bases/syntax)
494
+ - [Functions](https://help.obsidian.md/bases/functions)
495
+ - [Views](https://help.obsidian.md/bases/views)
496
+ - [Formulas](https://help.obsidian.md/formulas)
497
+ - [Complete Functions Reference](references/FUNCTIONS_REFERENCE.md)
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: obsidian-cli
3
+ description: Interact with Obsidian vaults using the Obsidian CLI to read, create, search, and manage notes, tasks, properties, and more. Also supports plugin and theme development with commands to reload plugins, run JavaScript, capture errors, take screenshots, and inspect the DOM. Use when the user asks to interact with their Obsidian vault, manage notes, search vault content, perform vault operations from the command line, or develop and debug Obsidian plugins and themes.
4
+ ---
5
+
6
+ # Obsidian CLI
7
+
8
+ Use the `obsidian` CLI to interact with a running Obsidian instance. Requires Obsidian to be open.
9
+
10
+ ## Command reference
11
+
12
+ Run `obsidian help` to see all available commands. This is always up to date. Full docs: https://help.obsidian.md/cli
13
+
14
+ ## Syntax
15
+
16
+ **Parameters** take a value with `=`. Quote values with spaces:
17
+
18
+ ```bash
19
+ obsidian create name="My Note" content="Hello world"
20
+ ```
21
+
22
+ **Flags** are boolean switches with no value:
23
+
24
+ ```bash
25
+ obsidian create name="My Note" silent overwrite
26
+ ```
27
+
28
+ For multiline content use `\n` for newline and `\t` for tab.
29
+
30
+ ## File targeting
31
+
32
+ Many commands accept `file` or `path` to target a file. Without either, the active file is used.
33
+
34
+ - `file=<name>` — resolves like a wikilink (name only, no path or extension needed)
35
+ - `path=<path>` — exact path from vault root, e.g. `folder/note.md`
36
+
37
+ ## Vault targeting
38
+
39
+ Commands target the most recently focused vault by default. Use `vault=<name>` as the first parameter to target a specific vault:
40
+
41
+ ```bash
42
+ obsidian vault="My Vault" search query="test"
43
+ ```
44
+
45
+ ## Common patterns
46
+
47
+ ```bash
48
+ obsidian read file="My Note"
49
+ obsidian create name="New Note" content="# Hello" template="Template" silent
50
+ obsidian append file="My Note" content="New line"
51
+ obsidian search query="search term" limit=10
52
+ obsidian daily:read
53
+ obsidian daily:append content="- [ ] New task"
54
+ obsidian property:set name="status" value="done" file="My Note"
55
+ obsidian tasks daily todo
56
+ obsidian tags sort=count counts
57
+ obsidian backlinks file="My Note"
58
+ ```
59
+
60
+ Use `--copy` on any command to copy output to clipboard. Use `silent` to prevent files from opening. Use `total` on list commands to get a count.
61
+
62
+ ## Plugin development
63
+
64
+ ### Develop/test cycle
65
+
66
+ After making code changes to a plugin or theme, follow this workflow:
67
+
68
+ 1. **Reload** the plugin to pick up changes:
69
+ ```bash
70
+ obsidian plugin:reload id=my-plugin
71
+ ```
72
+ 2. **Check for errors** — if errors appear, fix and repeat from step 1:
73
+ ```bash
74
+ obsidian dev:errors
75
+ ```
76
+ 3. **Verify visually** with a screenshot or DOM inspection:
77
+ ```bash
78
+ obsidian dev:screenshot path=screenshot.png
79
+ obsidian dev:dom selector=".workspace-leaf" text
80
+ ```
81
+ 4. **Check console output** for warnings or unexpected logs:
82
+ ```bash
83
+ obsidian dev:console level=error
84
+ ```
85
+
86
+ ### Additional developer commands
87
+
88
+ Run JavaScript in the app context:
89
+
90
+ ```bash
91
+ obsidian eval code="app.vault.getFiles().length"
92
+ ```
93
+
94
+ Inspect CSS values:
95
+
96
+ ```bash
97
+ obsidian dev:css selector=".workspace-leaf" prop=background-color
98
+ ```
99
+
100
+ Toggle mobile emulation:
101
+
102
+ ```bash
103
+ obsidian dev:mobile on
104
+ ```
105
+
106
+ Run `obsidian help` to see additional developer commands including CDP and debugger controls.