skills/obsidian-gh-knowledge/SKILL.md
Bootstrap and operate an Obsidian vault with official Obsidian CLI first, then local filesystem/git fallback, then GitHub API fallback when local access is unavailable. Use when Codex needs first-run workspace init from a confirmed vault repo URL, project-scoped note reads and writes, vault health and readability audits, or structure cleanup in this vault. Verify current Obsidian CLI and Help syntax with Context7 instead of guessing, and use DeepWiki only for related public repo exploration.
npx skillsauth add karlorz/agent-skills obsidian-gh-knowledgeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
## TL;DR, and must use Mermaid diagrams for visual explanations.5️⃣-Projects/GitHub/<project>/. See "Project Scoping (CRITICAL)" section below.scripts/local_obsidian_knowledge.py for repeatable local macOS workflows that combine Obsidian CLI operations with this vault's project rules and git sync.raw/ as a Git submodule, treat it as source-input storage rather than curated note space.raw/inbox is the default intake lane for external source material. 0️⃣-Inbox is curated staging for notes that already contain synthesis and still need routing.simplify-review first when the vault feels hard to read or hard to trust; it reconciles full-vault Obsidian counts with active-scope graph checks and overview readability audits.main, and record the sync outcome in today's daily log when the task is complete.raw/ submodule even when the Obsidian CLI is unavailable. Keep the baseline hook-free and clean up stale core.hooksPath config during bootstrap.graph TB
A[Start Vault Operation] --> B{Local vault exists}
B -- Yes --> C{Obsidian CLI ready}
B -- No --> D{Confirmed vault repo URL}
D -- Yes --> E[Clone vault into Documents]
D -- No --> F[Use GitHub mode]
E --> C
C -- Yes --> G[Use local CLI mode]
C -- No --> H[Use local git fallback]
G --> I[Run operation]
H --> I
F --> I
Use this skill to bootstrap and manage an Obsidian vault safely and consistently.
Keep the two inboxes semantically strict:
raw/inbox: clipped articles, copied posts, transcripts, imported markdown, and other preserved source material.0️⃣-Inbox: curated notes that already contain synthesis, project framing, or structured writeup but still need routing.Decision rule:
capture-raw into raw/inbox.capture into 0️⃣-Inbox or write directly into the final project folder.0️⃣-Inbox as a raw-material dumping ground.raw/ second./websites/help_obsidian_md_cli)https://help.obsidian.md/cli/indexhttps://obsidian.md/changelog/2026-02-27-desktop-v1.12.4/https://github.com/kepano/obsidian-skillsNote: CLI docs may still show early-access wording in some sections. Treat the public changelog (February 27, 2026) as the release marker.
Use the generic upstream skills and the local repo-specific skill for different jobs:
kepano/obsidian-skills/skills/obsidian-cli: canonical command syntax and current CLI feature surface.kepano/obsidian-skills/skills/obsidian-markdown: generic Obsidian-flavored Markdown authoring rules.kepano/obsidian-skills/skills/obsidian-bases: .base dashboards and structured knowledge views.obsidian-gh-knowledge in this repo: local vault bootstrap, project scoping, emoji-folder guardrails, git sync, and GitHub fallback.The local helper script scripts/local_obsidian_knowledge.py is the bridge between the upstream generic CLI patterns and this vault's repo-specific conventions.
~/Documents/<repo-name> for the current user, then write local_vault_path to config.obsidian CLI is available and enabled.This ordering is for compatibility across desktop, server, and sandbox environments.
VAULT_DIR:
~/.config/obsidian-gh-knowledge/config.json has local_vault_path, use it.~/Documents/obsidian_vault/.VAULT_DIR does not exist and the user has confirmed a vault repo URL, run the bootstrap script, then re-resolve VAULT_DIR.VAULT_DIR exists and prefer_local is not false, use local mode.command -v obsidian succeeds, andobsidian help succeeds (CLI is enabled and app connection works).Use one helper to find bundled scripts across repo-local and user-skill layouts:
resolve_obsidian_gh_script() {
local name="$1"
local path
for path in \
"skills/obsidian-gh-knowledge/scripts/$name" \
"agent-skills/skills/obsidian-gh-knowledge/scripts/$name" \
"scripts/$name" \
"$HOME/.agents/skills/obsidian-gh-knowledge/scripts/$name"
do
if [ -f "$path" ]; then
printf '%s\n' "$path"
return 0
fi
done
echo "Could not find obsidian-gh-knowledge script: $name" >&2
return 1
}
Use this workflow when a new workspace does not yet have the vault checked out locally.
Rules:
https://github.com/karlorz/obsidian_vault, prefer a local clone over GitHub-only mode.~/Documents/<repo-name>. For the example above, that becomes ~/Documents/obsidian_vault.~ is user-specific. If the current user is root, the default destination becomes /root/Documents/<repo-name>.--vault-dir only when the user explicitly wants a different destination.Run it after confirmation:
INIT_SCRIPT_PATH="$(resolve_obsidian_gh_script init_local_vault.py)"
python3 "$INIT_SCRIPT_PATH" \
--repo-url "https://github.com/karlorz/obsidian_vault" \
--repo-key personal
What the bootstrap script does:
~/Documents/<repo-name> unless the user provided --vault-dir.raw/ when --raw-submodule-url and --init-raw-submodule are provided.extensions.worktreeConfig=truecore.hooksPath config from shared and worktree-local Git configpush.recurseSubmodules=on-demandraw/ submodule when presentraw/ to its configured branch and upstream when safe to do so~/.config/obsidian-gh-knowledge/config.json:
local_vault_pathprefer_local to truedefault_repo if it is currently missingrepos.<key> if --repo-key is providedvault_name if it is currently missingraw_submodule_path and raw_submodule_url when raw-submodule bootstrap is usedOptional raw-submodule bootstrap:
python3 "$INIT_SCRIPT_PATH" \
--repo-url "https://github.com/karlorz/obsidian_vault" \
--repo-key personal \
--raw-submodule-url "https://github.com/karlorz/obsidian_vault_raw.git" \
--init-raw-submodule
After bootstrap, re-run mode selection and prefer local CLI or local git fallback from the new local_vault_path.
Notes:
obsidian is not installed.2>/dev/null); missing paths should be obvious.pwd, echo "$HOME", and ls -la "$(dirname "$VAULT_DIR")" before deciding between bootstrap and GitHub fallback.ls/list and copy the exact path.5️⃣-Projects (no space). 5️⃣ -Projects will break local ls and GitHub reads.read fails with "File not found", immediately list the parent folder or search for the filename instead of guessing.ls -1 "$VAULT_DIR" | rg -m1 "Projects$" (returns 5️⃣-Projects in this vault).local_vault_path until the user has confirmed the vault repo URL.[!warning] Common Mistake Agents often navigate to the wrong project folder (e.g., going to
trends/when working oncmux). This wastes context and confuses the user.
Rules for project-scoped operations:
Determine current project context FIRST before any vault operation:
/root/workspace -> look for CLAUDE.md or package.json to identify project)Scope ALL operations (reads AND writes) to the correct project folder:
5️⃣-Projects/GitHub/<project>/5️⃣-Projects/GitHub/cmux/5️⃣-Projects/GitHub/trends/Always read <project>/_Overview.md first to confirm you're in the right place before any other reads or writes.
Never cross project boundaries without explicit user request:
cmux, do not read/write to trends/ foldercmux/cmux-agent-dev-roadmap.md, NOT trends/trends-dev-roadmap.mdProject detection heuristic (in order):
# 1. Check if current workspace has project identifier
if [ -f "CLAUDE.md" ]; then
PROJECT=$(grep -m1 "project.*cmux\|project.*trends" CLAUDE.md | grep -oE "cmux|trends" | head -1)
fi
# 2. Check package.json name field
if [ -z "$PROJECT" ] && [ -f "package.json" ]; then
PROJECT=$(jq -r '.name // empty' package.json 2>/dev/null | grep -oE "cmux|trends" | head -1)
fi
# 3. Check git remote
if [ -z "$PROJECT" ]; then
PROJECT=$(git remote get-url origin 2>/dev/null | grep -oE "cmux|trends" | head -1)
fi
When listing project folders, always show what's available:
ls "$VAULT_DIR/5️⃣-Projects/GitHub/"
# Output: cmux data-labeling openclaw trends
Quick checks:
# Local vault path
python3 - <<'PY'
import json, os
p = os.path.expanduser('~/.config/obsidian-gh-knowledge/config.json')
if os.path.exists(p):
c = json.load(open(p))
print(os.path.expanduser(c.get('local_vault_path', '~/Documents/obsidian_vault')))
else:
print(os.path.expanduser('~/Documents/obsidian_vault'))
PY
# CLI availability
command -v obsidian
obsidian help
If obsidian help prints Command line interface is not enabled, use local filesystem fallback until enabled in Obsidian settings.
~/.config/obsidian-gh-knowledge/config.json and ~/Documents/obsidian_vault do not exist by default. Expect either bootstrap with a confirmed repo URL or explicit --repo usage.Do not block execution waiting for CLI in headless environments.
1.12+.Settings -> General -> Advanced -> Command line interface./Applications/Obsidian.app/Contents/MacOS.Unable to find helper app or Command line interface is not enabled, re-enable the CLI toggle in settings and restart the terminal. If commands succeed and only emit the helper warning, treat it as noise and continue.vault=<name> as the first parameter.file=<name> for wikilink-style resolution, or path=<exact/path.md> for precise targeting.Examples:
# Prefer running inside vault root
cd "$VAULT_DIR"
# Or target by vault name explicitly
obsidian vault="My Vault" search query="test"
# Exact file targeting
obsidian read path="5️⃣-Projects/GitHub/cmux/_Overview.md"
# Search and read
obsidian search query="MOC" path="5️⃣-Projects/" format=json
obsidian read path="5️⃣-Projects/GitHub/cmux/_Overview.md"
# Create/update content
obsidian create path="2️⃣-Drafts/new-note.md" content="# Title\n\n## TL;DR\n"
obsidian create path="2️⃣-Drafts/new-note.md" content="# Title\n\n## TL;DR\n- [ ] Follow up" overwrite
obsidian append path="2️⃣-Drafts/new-note.md" content="\n- [ ] Follow up"
# Move/rename and delete
obsidian move path="0️⃣-Inbox/note.md" to="5️⃣-Projects/GitHub/cmux/note.md"
obsidian delete path="2️⃣-Drafts/tmp-note.md"
# Tasks, tags, properties, templates, daily note
obsidian tasks path="5️⃣-Projects/GitHub/cmux/_Overview.md" todo format=json
obsidian tags counts
obsidian properties path="5️⃣-Projects/GitHub/cmux/_Overview.md"
obsidian templates
obsidian template:read name="github-project-template"
obsidian daily
obsidian daily:append content="- [ ] Review inbox"
For common macOS workflows, prefer the repo-specific helper over hand-building command sequences:
LOCAL_WRAPPER="$(resolve_obsidian_gh_script local_obsidian_knowledge.py)"
python3 "$LOCAL_WRAPPER" doctor
python3 "$LOCAL_WRAPPER" dashboard
python3 "$LOCAL_WRAPPER" review
python3 "$LOCAL_WRAPPER" simplify-review
python3 "$LOCAL_WRAPPER" audit
python3 "$LOCAL_WRAPPER" fix-tldr --dry-run
python3 "$LOCAL_WRAPPER" structure-report --dry-run
python3 "$LOCAL_WRAPPER" structure-fix --dry-run
python3 "$LOCAL_WRAPPER" archive-fix --dry-run
python3 "$LOCAL_WRAPPER" capture-raw "Clipped article" --source "https://example.com/post"
python3 "$LOCAL_WRAPPER" capture "Curated summary note"
python3 "$LOCAL_WRAPPER" project-note cmux "Feature review"
python3 "$LOCAL_WRAPPER" organize "0️⃣-Inbox/feature-review.md" cmux
python3 "$LOCAL_WRAPPER" sync --message "Update vault notes"
--vault-dir is a global option. If you need it, place it before the subcommand, for example python3 "$LOCAL_WRAPPER" --vault-dir "$VAULT_DIR" doctor.
Wrapper responsibilities:
raw/ submodule health in doctor when configured.push.recurseSubmodules.obsidian CLI when available.doctor still reports local Git/bootstrap readiness for remote or headless workspaces.review summary with vault health metrics, task counts, recent files, unresolved-link samples, and explicit raw-vs-curated intake counts.dashboard and review orphan/dead-end numbers as Obsidian full-vault signals, not the precise cleanup scope for active notes.simplify-review that layers review, audit, active-scope structure analysis, overview readability checks, and duplicate basename/alias detection into one report note.audit for required folders, project _Overview.md coverage, ## TL;DR placement, oversized MOCs, stale Structure Cleanup Inbox backlogs, and YAML frontmatter parsing.## TL;DR sections into notes that are missing one._Overview.md and adding orphan notes to auto-generated cleanup sections inside project MOCs._Archive-Index.md notes and backlink archived notes so archive folders stay navigable without polluting active MOCs.raw/ subtree in readability and TL;DR audits because raw materials are source input, not curated notes.raw/inbox as the default intake lane for external source material and 0️⃣-Inbox as curated staging._Overview.md before project-scoped note creation or organization.obsidian move so note moves happen inside Obsidian instead of raw shell renames.local_vault_git_sync.py.--allow-dirty-submodules only when you mean it.obsidian read ...)./root/lifecycle/memory/daily/<YYYY-MM-DD>.md when the vault workflow or task context expects it.Recommended (one command):
LOCAL_SYNC_SCRIPT="$(resolve_obsidian_gh_script local_vault_git_sync.py)"
python3 "$LOCAL_SYNC_SCRIPT" \
--vault-dir "$VAULT_DIR" \
--message "Update vault notes"
Manual workflow:
cd "$VAULT_DIR"
# If raw/ has changes: commit+push inside raw/ first, then return to parent.
git -C raw status --porcelain=v1 # use `git -C`, not `cd raw` — Bash CWD persists
# git -C raw add -A && git -C raw commit -m "..." && git -C raw push
git pull --rebase --autostash
git status --porcelain=v1
git add -A # includes bumped raw/ submodule pointer
git commit -m "Update vault notes"
git pull --rebase
git push
If git push is rejected because the remote advanced, fetch/rebase onto the new origin/main tip and retry the push. Do not resolve that by force-pushing.
Use only when local CLI cannot be used.
VAULT_DIR="$HOME/Documents/obsidian_vault"
ls -la "$VAULT_DIR"
rg -n "keyword" "$VAULT_DIR"
sed -n '1,160p' "$VAULT_DIR/5️⃣-Projects/GitHub/cmux/_Overview.md"
For edits, use the same sync workflow as local CLI mode (commit + pull/rebase + push).
Use when local vault is unavailable or prefer_local is explicitly false.
GitHub read protocol (prevents "File not found"):
list the parent folder to copy the exact pathsearch for the filename/keyword if unknownread using the returned exact pathResolve repo in this order:
--repo <owner/repo> if provided.--repo <key> (no /) resolved from repos.<key> in config.default_repo from config.Never guess repo names.
ghgh auth statusgh repo view <owner/repo> >/dev/nullSCRIPT_PATH="$(resolve_obsidian_gh_script github_knowledge_skill.py)"
python3 "$SCRIPT_PATH" \
--repo <owner/repo> <command> [args]
Available commands:
list --path <path>read <file_path>search <query>move <src> <dest> --branch <branch_name> --message <commit_msg>copy <src> <dest> --branch <branch_name> --message <commit_msg>write <file_path> --stdin|--from-file <path> --branch <branch_name> --message <commit_msg>Run these before substantial work in sandboxes:
command -v obsidian || true
gh auth status
python3 "$SCRIPT_PATH" --repo <owner/repo> list --path ""
python3 "$SCRIPT_PATH" --repo <owner/repo> read "README.md"
python3 "$SCRIPT_PATH" --repo <owner/repo> search "filename:_Overview.md"
Expected behavior from recent validation:
obsidian is often unavailable in headless Linux.--repo is explicit and gh has access.python3 "$SCRIPT_PATH" --repo <owner/repo> list --path "0️⃣-Inbox"main."..."), especially emoji folders.list first.list on repo root also fails, treat it as repo permission or wrong account/team context, not just path typo.If repository-level AGENTS.md exists, follow it first.
## TL;DR near the top for human scanning.graph TB or sequenceDiagram) to visually explain architectures, workflows, or complex concepts.[[note-title]]) for internal notes.graph TB / sequenceDiagram.subgraph "Title" (avoid subgraph ID[Label]).\n in labels; use <br/> or single-line labels.CMUX_DB, OC_GW).Each project folder under 5️⃣-Projects/ must include _Overview.md as MOC.
When creating a project folder:
GitHub, Infrastructure, Research)._Overview.md first._Overview.md.For GitHub project notes, use 100-Templates/github-project-template.md.
GitHub mode example:
python3 ~/.agents/skills/obsidian-gh-knowledge/scripts/github_knowledge_skill.py \
--repo <owner/repo> read "100-Templates/github-project-template.md"
Prefer creating ~/.config/obsidian-gh-knowledge/config.json via scripts/init_local_vault.py on first-run. Hand-edit the file only when you need to adjust repos or vault naming.
Config shape:
{
"default_repo": "<owner>/<vault-repo>",
"repos": {
"personal": "<owner>/<vault-repo>",
"work": "<org>/<work-vault-repo>"
},
"local_vault_path": "~/Documents/obsidian_vault",
"prefer_local": true,
"vault_name": "My Vault"
}
vault_name is optional; use it when running CLI commands outside the vault directory.
See references/obsidian-organizer.md for concrete note-organization workflow patterns.
development
Review and simplify recently changed code for reuse, clarity, and efficiency while preserving behavior. Use when the user asks to simplify, refine, polish, clean up, or make code clearer, or after finishing a logical chunk of implementation that should be tightened before commit.
tools
Use this skill when the user asks to open a browser, browse a website, scrape a page, automate Chrome, take a screenshot, fill out a form, click a button, or otherwise interact with a website. Includes a browser-worker agent (model: sonnet) for mechanical Chrome lifecycle and interaction tasks.
development
Host-level backup and restore with profile system (presets + custom YAML profiles), model-aware agents (sonnet worker for mechanical tasks), post-discovery research, and skillwiki infrastructure capture. Uses rsync with partial-dir for resumable WAN transfers. Use when backing up or restoring Caddy reverse-proxy domains, databases (postgres, mysql, redis, mongodb, sqlite), systemd services, full SSH identity/config, Tailscale state/config, and Hermes agent state on remote Linux hosts.
tools
Hermes Agent CLI commands reference. Use when the user asks about hermes-agent CLI usage, commands, flags, or subcommands. Covers the full hermes terminal command surface.