obsidian-cli
Skill534 starsChanged 36 days agoMITView on GitHub
Use the Obsidian CLI to debug, inspect, and test Obsidian plugins during development. Covers plugin reloading, console inspection, runtime evaluation, driving the UI (commands, CDP, screenshots, mobile emulation), frontmatter properties, and common debugging recipes for the gemini-scribe plugin.
We split this skill into the rules it gives an agent
11 rules. 0 are common, 0 are distinctive, and 11 are very specific to this project.
0
Common
Most of the 72 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 61
Use eval to run JavaScript against the live Obsidian instance.
- Very specific: line 141
If wait_for_eval gives up, stop and investigate (check the app window, obsidian dev:errors) rather than testing against a half-applied …
- Very specific: line 147
Use the property:* family for frontmatter reads/writes — it goes through Obsidian's property cache, so it stays in sync with the metadata …
- Very specific: line 279
Remove data.json to simulate a new install, then reload:
- Very specific: line 423
Always preflight with obsidian eval code="app.vault.getName()" — no vault= flag, just read what's actually focused.
- Very specific: line 451
Use \n for newline and \t for tab in content values
- Very specific: line 457
dev:mobiletoggles when called with no argument: Always pass on or off. The state persists across CLI invocations and across Obsidian … - Very specific: line 470
Modals stack: If a previous test left a modal open, the next screenshot will be wrong.
- Very specific: line 486
Check that the plugin ID is correct (gemini-scribe, not obsidian-gemini) and that the plugin is enabled:
- Very specific: line 494
Use obsidian commands filter=<prefix> to confirm the ID.
- Very specific: line 502
Run obsidian dev:mobile off and then reload.
“Common” is measured: kept by at least 6 in 10 of the 72 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Obsidian CLI
The Obsidian CLI (obsidian command) provides direct access to a running Obsidian instance from the terminal. It's invaluable for plugin development — you can reload plugins, inspect state, evaluate expressions, drive the UI (open modals, click, type, screenshot), toggle mobile emulation, and view console output without leaving your editor.
The CLI surface is large (100+ commands) and growing. Run obsidian help periodically to spot new capabilities, and obsidian help <command> for per-command flags. Never use obsidian <command> --help — the CLI runs the command rather than printing its help (see Footguns). This skill documents the parts most useful for plugin work.
When to use this skill
- Debugging runtime errors during plugin development
- Verifying plugin state after code changes
- Testing migration logic or settings changes
- Inspecting secrets, settings, and vault state
- Reloading the plugin after a rebuild
- Viewing console errors without opening DevTools
- Driving UI surfaces (open modals, click buttons, type into inputs) for automated testing
- Taking screenshots for regression checks or PR descriptions
- Testing mobile-only code paths from a desktop session
Quick reference
Plugin development essentials
# Reload the plugin after rebuilding (use after `npm run build` or `npm run dev`)
obsidian plugin:reload id=gemini-scribe
# Enable DevTools debugger (programmatic CDP attach — does NOT open the DevTools window)
obsidian dev:debug on
# Open the Electron DevTools window itself (toggle — see footgun note below)
obsidian devtools
# View recent console output (errors, warnings, logs)
obsidian dev:console
obsidian dev:console level=error
obsidian dev:console level=warn
obsidian dev:console limit=100
# View captured errors
obsidian dev:errors
# Clear console buffer
obsidian dev:console clearEvaluating expressions
Use eval to run JavaScript against the live Obsidian instance. The expression has access to the full app object.
# Basic eval
obsidian eval code="app.vault.getName()"
# Check plugin is loaded
obsidian eval code="app.plugins.plugins['gemini-scribe'] !== undefined"
# Read plugin settings
obsidian eval code="JSON.stringify(app.plugins.plugins['gemini-scribe'].settings, null, 2)"
# Check the plugin's API key (via SecretStorage getter)
obsidian eval code="app.plugins.plugins['gemini-scribe'].apiKey"Driving the UI (commands, CDP, screenshots)
The command and dev:cdp commands turn the CLI into a remote control. Combined with dev:screenshot, this is how you exercise UI surfaces from a script (or an agent).
# Execute any registered Obsidian command (palette entry) by ID
obsidian command id=gemini-scribe:open-scheduler
obsidian command id=command-palette:open
# List all available commands (use to verify an ID exists before depending on it)
obsidian commands
obsidian commands filter=gemini-scribe
# Take a screenshot of the current Obsidian window.
# path= is resolved against the VAULT root, not your shell's cwd — pass an absolute path
# unless you really want the PNG inside the vault.
obsidian dev:screenshot path="$PWD/debug-screenshot.png"
# Inspect the DOM
obsidian dev:dom selector=".gemini-agent-view"
obsidian dev:dom selector=".gemini-agent-input" text
obsidian dev:dom selector=".gemini-agent-view" css=display
obsidian dev:dom selector=".scheduler-row" total
# Drive the UI via Chrome DevTools Protocol (clicks, key events, raw evals)
obsidian dev:cdp method=Input.dispatchMouseEvent params='{"type":"mousePressed","x":100,"y":200,"button":"left","clickCount":1}'
obsidian dev:cdp method=Input.dispatchMouseEvent params='{"type":"mouseReleased","x":100,"y":200,"button":"left","clickCount":1}'
obsidian dev:cdp method=Input.insertText params='{"text":"Hello"}'dev:cdp is escape-hatch level — if command + eval + dev:dom get you what you need, prefer those for readability. Reach for CDP when you need precise mouse coordinates (e.g. clicking inside a canvas) or keyboard events the DOM API doesn't expose well.
Mobile emulation
Toggles desktop into mobile-emulated mode so platform-gated code paths (Platform.isMobile, mobile-only CSS, mobile UI affordances) become testable.
obsidian dev:mobile on # Enable mobile emulation. The app reloads automatically.
obsidian dev:mobile off # Disable. The app reloads automatically.Because each toggle reloads the whole app, every open modal and all in-memory plugin state are gone afterwards, and CLI calls issued mid-reload can hang. Wait for it to settle and confirm the mode actually applied before testing anything. Poll with a bounded helper: each call is wrapped in the Perl alarm (see Footguns), a call that times out or errors counts as "not ready yet", and the loop gives up with a clear message instead of spinning forever:
# wait_for_eval <expected> <js>: poll `obsidian eval` until it prints <expected>.
# Each call is capped at 10s by the Perl alarm (macOS has no `timeout`); a hung or failed
# call is treated as "not ready yet". Gives up after 20 attempts (~4 min worst case).
wait_for_eval() {
expected=$1; js=$2; out=""
for attempt in $(seq 1 20); do
out=$(perl -e 'alarm shift; exec @ARGV' 10 obsidian eval code="$js" 2>/dev/null | sed 's/^=> //')
[ "$out" = "$expected" ] && return 0
sleep 2
done
echo "Gave up after 20 attempts: '$js' never printed '$expected' (last output: '$out')." >&2
return 1
}
# After `dev:mobile on`: mobile class present and the plugin is back
wait_for_eval true "document.body.classList.contains('is-mobile') && Boolean(app.plugins.plugins['gemini-scribe'])"
# After `dev:mobile off`: mobile class gone and the plugin is back
wait_for_eval true "document.body.classList.contains('is-mobile') === false && Boolean(app.plugins.plugins['gemini-scribe'])"If wait_for_eval gives up, stop and investigate (check the app window, obsidian dev:errors) rather than testing against a half-applied toggle.
Footgun: invoking obsidian dev:mobile with no argument toggles the current state — that's how you accidentally enable it. Always pass on or off explicitly. Always toggle off when you're done — the flag persists across CLI invocations and silently changes the app's behaviour for whoever next opens it.
Frontmatter properties
Use the property:* family for frontmatter reads/writes — it goes through Obsidian's property cache, so it stays in sync with the metadata index. Don't reach for read + manual YAML parsing for properties.
# Read all unique property names known to the vault
obsidian properties
# Read a single property from a file
obsidian property:read name=schedule path="gemini-scribe/Scheduled-Tasks/daily-summary.md"
# Set a property (creates it if it doesn't exist)
obsidian property:set name=enabled value=true type=checkbox path="gemini-scribe/Scheduled-Tasks/daily-summary.md"
# Remove a property
obsidian property:remove name=lastRunAt path="gemini-scribe/Scheduled-Tasks/daily-summary.md"type= is one of text|list|number|checkbox|date|datetime. For frontmatter changes from a plugin, prefer app.fileManager.processFrontMatter() (project convention — see AGENTS.md); the CLI is for ad-hoc testing.
Hotkeys
obsidian hotkey id=gemini-scribe:open-scheduler # what's bound to this command?
obsidian hotkeys # all hotkeys
obsidian hotkeys all verbose # include commands without hotkeys, mark custom vs defaultSecret storage
# List all secrets in the vault
obsidian eval code="app.secretStorage.listSecrets()"
# Read a specific secret value
obsidian eval code="app.secretStorage.getSecret('my-secret-name')"
# Set a secret
obsidian eval code="app.secretStorage.setSecret('my-secret-name', 'my-secret-value')"Vault and file operations
# Vault info
obsidian vault
# List vaults (desktop only)
obsidian vaults
# List files
obsidian files
obsidian files folder=gemini-scribe
obsidian files ext=md total
# Read a file
obsidian read path="gemini-scribe/Agent-Sessions/session.md"
# CRUD (useful for setting up test fixtures)
obsidian create name=test-task path="gemini-scribe/Scheduled-Tasks/test-task.md" content="..."
obsidian append path="some-file.md" content="more text"
obsidian prepend path="some-file.md" content="prefix"
obsidian rename path="old.md" name=new.md
obsidian move path="some-file.md" folder=archive
obsidian delete path="some-file.md"
# Open a file in the editor
obsidian open path="gemini-scribe/Agent-Sessions/session.md" newtab
# Search vault contents
obsidian search query="apiKey"
obsidian search:context query="apiKey" limit=5
# Check file info
obsidian file path="data.json"
# Tab management
obsidian tabs
obsidian tab:open path="..."Plugin management
# List all plugins
obsidian plugins
obsidian plugins filter=community versions
# Get plugin info
obsidian plugin id=gemini-scribe
# Enable/disable
obsidian plugin:enable id=gemini-scribe
obsidian plugin:disable id=gemini-scribe
# Reload after code changes
obsidian plugin:reload id=gemini-scribe
# Install/uninstall community plugins (for testing compatibility)
obsidian plugin:install id=some-plugin enable
obsidian plugin:uninstall id=some-plugin
# Restricted mode (toggle or check)
obsidian plugins:restrict on
obsidian plugins:restrict off
obsidian plugins:restrict # report current stateApp lifecycle
obsidian reload # Reload the current vault (preserves Obsidian process)
obsidian restart # Restart the Obsidian app entirelyplugin:reload id=gemini-scribe is almost always what you want during development. Reach for reload / restart only when investigating something that survives a per-plugin reload.
CSS snippets and themes
Useful when verifying the plugin doesn't break with non-default themes or third-party styling.
obsidian themes # installed themes
obsidian theme:set name="Catppuccin" # switch theme
obsidian snippets # installed snippets
obsidian snippets:enabled # only enabled
obsidian snippet:enable name="my-overrides"
obsidian snippet:disable name="my-overrides"Common recipes
Test a fresh install
Remove data.json to simulate a new install, then reload:
# Remove plugin settings (simulates fresh install)
obsidian eval code="app.vault.adapter.remove('.obsidian/plugins/gemini-scribe/data.json')"
# Reload the plugin
obsidian plugin:reload id=gemini-scribe
# Verify settings are defaults
obsidian eval code="JSON.stringify(app.plugins.plugins['gemini-scribe'].settings, null, 2)"Debug a settings migration
# Check current settings before migration
obsidian eval code="JSON.stringify(app.plugins.plugins['gemini-scribe'].settings, null, 2)"
# Rebuild and reload
npm run build && obsidian plugin:reload id=gemini-scribe
# Check settings after migration
obsidian eval code="JSON.stringify(app.plugins.plugins['gemini-scribe'].settings, null, 2)"
# Check console for migration logs
obsidian dev:console level=logVerify a documented command exists
Useful before depending on a command ID in a doc, test, or skill:
obsidian commands filter=gemini-scribe # quick visual check
obsidian commands filter=gemini-scribe-ope # narrower
obsidian eval code="Boolean(app.commands.findCommand('gemini-scribe:open-scheduler'))"Open a UI surface and screenshot it
Pattern: trigger → settle → screenshot → inspect → close.
# Trigger
obsidian command id=gemini-scribe:open-scheduler
# Settle (animations, lazy renders)
sleep 1
# Screenshot (absolute path — path= is vault-relative otherwise)
obsidian dev:screenshot path="$PWD/scheduler-modal.png"
# Inspect DOM
obsidian dev:dom selector=".gemini-scheduler-schedule-row" text
# Close: Escape at the focused element (there is no .modal-close-button to click)
obsidian eval code="(document.activeElement||document.body).dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',code:'Escape',bubbles:true}))"
obsidian eval code="document.querySelectorAll('.modal-container').length" # expect 0; repeat Escape per stacked modalTest a mobile-only code path
# wait_for_eval: the bounded poll helper defined under "Mobile emulation" above
obsidian dev:mobile on # reloads the whole app — platform-gated code re-runs on its own
sleep 3
wait_for_eval true "document.body.classList.contains('is-mobile') && Boolean(app.plugins.plugins['gemini-scribe'])" \
|| exit 1 # never test while the toggle is half-applied
obsidian dev:screenshot path="$PWD/mobile-view.png"
# … exercise the mobile path …
obsidian dev:mobile off # ALWAYS revert (reloads again)
sleep 3
wait_for_eval true "document.body.classList.contains('is-mobile') === false && Boolean(app.plugins.plugins['gemini-scribe'])" || exit 1Click a specific button via the DOM
Most of the time command + eval is enough. When you need an actual click (e.g. an event handler that requires a real mouse event), grab the element's bounding rect and use CDP:
obsidian eval code="(() => { const el = document.querySelector('.gemini-scheduler-new-btn'); if (!el) return null; const r = el.getBoundingClientRect(); return {x: r.x + r.width/2, y: r.y + r.height/2}; })()"
# Then dispatch a mouse press + release at those coords via dev:cdp Input.dispatchMouseEventFor most click-equivalent needs, eval code="document.querySelector('...').click()" is simpler and works fine.
Simulate the catch-up modal
Useful for exercising PR #723's auto-open-on-mobile behavior or any catch-up code path without waiting for real overdue tasks:
# 1. Snapshot current state file (so you can restore it)
obsidian read path="gemini-scribe/Scheduled-Tasks/scheduled-tasks-state.json" > /tmp/state-backup.json
# 2. Plant an overdue nextRunAt
obsidian eval code="(async () => {
const path = 'gemini-scribe/Scheduled-Tasks/scheduled-tasks-state.json';
const cur = JSON.parse(await app.vault.adapter.read(path));
Object.values(cur)[0].nextRunAt = new Date(Date.now() - 60_000).toISOString();
await app.vault.adapter.write(path, JSON.stringify(cur, null, 2));
})()"
# 3. Reload the plugin to trigger handleCatchUp()
obsidian plugin:reload id=gemini-scribe
# 4. Restore (after you're done observing)
obsidian eval code="app.vault.adapter.write('gemini-scribe/Scheduled-Tasks/scheduled-tasks-state.json', $(cat /tmp/state-backup.json | jq -Rs .))"
obsidian plugin:reload id=gemini-scribeInspect agent session state
# List session files
obsidian files folder=gemini-scribe/Agent-Sessions
# Check current session context
obsidian eval code="JSON.stringify(app.plugins.plugins['gemini-scribe'].agentView?.currentSession?.context, null, 2)"Check for errors after a change
# Full cycle: build, reload, check for errors
npm run build && obsidian plugin:reload id=gemini-scribe && sleep 1 && obsidian dev:errorsRead or modify a frontmatter property
obsidian property:read name=schedule path="gemini-scribe/Scheduled-Tasks/daily-summary.md"
obsidian property:set name=enabled value=false type=checkbox path="gemini-scribe/Scheduled-Tasks/daily-summary.md"
obsidian property:remove name=outputPath path="gemini-scribe/Scheduled-Tasks/daily-summary.md"Target a specific vault
Critical: empirically (verified May 2026) the vault=<name> flag does not actually route by name. The CLI always targets the currently focused Obsidian window, regardless of what's passed. obsidian vaults lists every registered vault; that list is informational only — you cannot redirect a CLI call to a non-focused vault. This may change in a future Obsidian release — re-verify periodically.
What this means in practice:
- To target a specific vault, make it the focused Obsidian window first (click it, or use macOS
Cmd-Tab/ WindowsAlt-Tab). - The
vault=<name>flag is effectively decorative right now. Continue passing it (it documents intent and may start working in a future release), but don't trust it. - Always preflight with
obsidian eval code="app.vault.getName()"— novault=flag, just read what's actually focused.
obsidian vaults # all registered vaults (open or not)
obsidian eval code="app.vault.getName()" # what the CLI will ACTUALLY hit (focused vault)Canonical preflight guard for any script or skill that's about to do destructive work:
EXPECTED="Test Vault"
ACTIVE=$(obsidian eval code="app.vault.getName()" | sed 's/^=> //')
if [ "$ACTIVE" != "$EXPECTED" ]; then
echo "Aborting: focused vault is \"$ACTIVE\", expected \"$EXPECTED\"." >&2
echo "Switch your Obsidian focus to \"$EXPECTED\" (Cmd-Tab on macOS) and retry." >&2
exit 1
fiMultiple Obsidian windows can run simultaneously (one per vault). Open the test vault in its own window and switch to it before running automated checks against it.
CLI syntax notes
- Arguments use
key=valueformat (no dashes) - Quote values containing spaces:
code="app.vault.getName()" - Boolean flags are bare keywords:
obsidian files total - File resolution:
file=resolves by name (like wikilinks),path=is exact - Most commands default to the active file when
file/pathis omitted - Use
\nfor newline and\tfor tab in content values obsidian help <cmd>prints the command's full parameter list — discover this rather than guess.obsidian helplists every command. Noteobsidian help <unknown>printsNo commands matching "<unknown>".and still exits 0, so check its output, not$?
Footguns
- Never probe a command with
--help.obsidian <cmd> --helpis not a help flag — the CLI runs the command (empirical, Sep 2026:dev:mobile --helptoggled mobile emulation and reloaded the app). Treat every command (includingplugin:reloadanddev:debug) as unsafe to probe that way. Useobsidian help <cmd>, which only prints. dev:mobiletoggles when called with no argument. Always passonoroff. The state persists across CLI invocations and across Obsidian restarts. Toggle off as soon as you're done with the mobile sub-pass.dev:mobile on|offreloads the app. Open modals and in-memory state are lost, and calls issued mid-reload can hang. Polldocument.body.classList.contains('is-mobile')with the boundedwait_for_evalhelper (see Mobile emulation) until it matches the mode you asked for before testing — never record results after a half-applied toggle.dev:screenshot path=is vault-relative. A relative path lands the PNG inside the vault (empirical, Sep 2026). Pass an absolute path.- Read toggle state from the label, not the input. Obsidian's settings toggles are a
label.checkbox-containerthat gainsis-enabledwhen on; the hiddeninput.checkedisn't a reliable read of what the user sees (empirical, Sep 2026). Assert withel.classList.contains('is-enabled'). - CLI calls can hang. A call issued while the app is reloading can block indefinitely, and macOS has no
timeoutbinary. Wrap calls in scripts with a Perl alarm:perl -e 'alarm shift; exec @ARGV' 20 obsidian eval code="..."(exits non-zero if the alarm fires). devtoolstoggles when called with no argument. Same pattern — leaves the DevTools window open or shut depending on prior state. If you need a known state, query first viaobsidian eval code="!!document.querySelector('.is-developer-tools-open')"or just call it twice.dev:debug on≠ opening DevTools. It attaches a Chrome DevTools Protocol debugger so commands likedev:cdpwork. To open the actual DevTools window, usedevtools.plugin:reloadreturns success even when the plugin'sonloadthrew. Always follow withobsidian dev:errors(ordev:console level=error) to confirm a clean load.commandslists every Obsidian command, not just plugin-owned ones. Filter withfilter=<prefix>to narrow.vaultsis desktop-only. Returns "only available on desktop" if invoked in a non-desktop context.- Some commands are plugin-conditional. For example,
dev:cssexists only when a particular dev plugin is enabled; the CLI returns "Command 'dev:css' not found. It may require a plugin to be enabled." Don't depend on conditional commands without first checking they're available. vault=<name>does not actually route by name. Empirically the CLI always targets the focused Obsidian window regardless of whatvault=is set to. The flag does not error on a bogus value, does not error on a real-but-different-vault value — it just silently hits the focused window. To target a specific vault, focus its Obsidian window first. Always preflight withobsidian eval code="app.vault.getName()"(novault=flag — read the truth) and assert it matches the expected vault before any destructive command. See "Target a specific vault" for the canonical guard.- There is no
.modal-close-button. Clicking it is a silent no-op (empirical, Sep 2026). Close a modal by dispatching Escape at the focused element:obsidian eval code="(document.activeElement||document.body).dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',code:'Escape',bubbles:true}))". - Modals stack. If a previous test left a modal open, the next screenshot will be wrong. One Escape closes only the topmost modal, so repeat the dispatch until
document.querySelectorAll('.modal-container').lengthis 0 before opening a new surface. - Screenshot timing. DOM updates are async.
sleep 1is the floor; for animations or first-time renders,sleep 2. If a screenshot looks blank, retry with a longer settle. reloadreloads the vault;restartrestarts the app.plugin:reload id=...is what you almost always want during development. Don't reach forreload/restartunless investigating something that survives a per-plugin reload.
Troubleshooting
CLI not found
The Obsidian CLI requires Obsidian desktop. Ensure it's installed and accessible from your terminal. Check obsidian version to verify.
Eval returns undefined
The expression may not return a value. Wrap in JSON.stringify() for objects, or ensure the expression actually produces a result. For async expressions, wrap in an IIFE: code="(async () => { … return result; })()".
Plugin not found after reload
Check that the plugin ID is correct (gemini-scribe, not obsidian-gemini) and that the plugin is enabled:
obsidian plugins:enabled filter=communityCommand ID does not exist
Use obsidian commands filter=<prefix> to confirm the ID. Plugin commands are namespaced — gemini-scribe:open-scheduler, not open-scheduler. The plugin must be enabled for its commands to register.
Screenshot is blank or stale
Settle longer (sleep 2+) and confirm the DOM actually has what you expect via dev:dom selector=.... If the screenshot still looks wrong, take a baseline first (dev:screenshot path="$PWD/before.png") so you can diff against the expected state.
Mobile emulation appears stuck on
Run obsidian dev:mobile off and then reload. If you don't know whether it was last toggled on or off, obsidian eval code="document.body.classList.contains('is-mobile')" will tell you.
Other versions81 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 81
- kepano/obsidian-skills★ 49ksame name
- breferrari/obsidian-mind★ 5.4ksame name
- Atmosphere/atmosphere★ 3.8ksame name
- pedronauck/skills★ 641same name
- sd0xdev/sd0x-dev-flow★ 192same name
- sd0xdev/sd0x-harness★ 192same name
- edrickleong/obsidian-calendar-bases★ 186same name
- benoror/obsidianos_work★ 166same name
- kv0906/pm-kit★ 138same name
- songzhuozhu/obsidian-llm-wiki★ 121same name
71 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use obsidian-bases, json-canvas and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
wangzhuofengSkillobsidian-bases
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.
Also in 45 projects that use this
wangzhuofengSkilljson-canvas
Create and edit JSON Canvas files (.canvas) with nodes, edges, groups, and connections. Use when working with .canvas files, creating visual canvases, mind maps, flowcharts, or when the user mentions Canvas files in Obsidian.
Also in 34 projects that use this
HK-hubSkilldefuddle
Extract clean markdown content from web pages using Defuddle CLI, removing clutter and navigation to save tokens. Use instead of WebFetch when the user provides a URL to read or analyze, for online documentation, articles, blog posts, or any standard web page.
Also in 33 projects that use this
lucasmaher-hashSkillknap
Render Markdown from templates and structured data using Knap CLI. Use when the user asks to apply a Knap template, turn JSON or CSV data into notes, batch-generate Markdown files, or format Defuddle output into a note.
Also in 4 projects that use this
BCS1037Skillmermaid-visualizer
Transform text content into professional Mermaid diagrams for presentations and documentation. Use when users ask to visualize concepts, create flowcharts, or make diagrams from text. Supports process flows, system architectures, comparisons, mindmaps, and more with built-in syntax error prevention.
Also in 4 projects that use this
0xHoneyJarSkillqmd
Local markdown search engine for knowledge bases, notes, and documentation. Combines BM25 full-text search, vector semantic search, and LLM re-ranking. Use when searching through markdown notes, retrieving documents, or managing knowledge collections.
Also in 4 projects that use this
- +1 more from wangzhuofeng
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- eval-harnessSkill
- gemini-api-devSkill
- obsidian-plugin-developmentSkill
- plugin-testSkill
- triage-issuesSkill
- ui-ux-guidelinesSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

