summaryrefslogtreecommitdiffhomepage
path: root/src/context
diff options
context:
space:
mode:
Diffstat (limited to 'src/context')
-rw-r--r--src/context/obsidian-markdown-rules.json115
-rw-r--r--src/context/system-prompt.json73
-rw-r--r--src/context/tools/batch-delete-file.json25
-rw-r--r--src/context/tools/batch-edit-file.json25
-rw-r--r--src/context/tools/batch-grep-search.json25
-rw-r--r--src/context/tools/batch-move-file.json25
-rw-r--r--src/context/tools/batch-search-files.json25
-rw-r--r--src/context/tools/batch-set-frontmatter.json25
-rw-r--r--src/context/tools/create-file.json28
-rw-r--r--src/context/tools/delete-file.json24
-rw-r--r--src/context/tools/edit-file.json32
-rw-r--r--src/context/tools/get-current-note.json19
-rw-r--r--src/context/tools/grep-search.json28
-rw-r--r--src/context/tools/move-file.json28
-rw-r--r--src/context/tools/read-file.json24
-rw-r--r--src/context/tools/search-files.json24
-rw-r--r--src/context/tools/set-frontmatter.json28
-rw-r--r--src/context/vault-context-template.json13
18 files changed, 586 insertions, 0 deletions
diff --git a/src/context/obsidian-markdown-rules.json b/src/context/obsidian-markdown-rules.json
new file mode 100644
index 0000000..a6244ce
--- /dev/null
+++ b/src/context/obsidian-markdown-rules.json
@@ -0,0 +1,115 @@
+{
+ "obsidianMarkdownRules": {
+ "header": "OBSIDIAN-SPECIFIC MARKDOWN SYNTAX:",
+ "description": "Obsidian extends standard Markdown with unique syntax. You already know standard Markdown (headings, bold, italic, lists, code blocks, tables, etc.). The rules below cover ONLY the Obsidian-specific extensions you MUST get right.",
+
+ "internalLinks": {
+ "header": "INTERNAL LINKS (WIKILINKS)",
+ "syntax": [
+ "[[Note Name]] — basic link",
+ "[[Note Name|Display Text]] — pipe separates target from display text (NO spaces around pipe)",
+ "[[Note Name#Heading]] — link to heading (hash INSIDE brackets)",
+ "[[Note Name#Heading#Subheading]] — chain hashes for nested headings",
+ "[[Note Name#^block-id]] — link to a block identifier",
+ "[[#Heading]] — link to heading in same note",
+ "[[#^block-id]] — link to block in same note"
+ ],
+ "commonMistakes": [
+ "WRONG: [[Note Name | Display Text]] with spaces around pipe. CORRECT: [[Note Name|Display Text]]",
+ "WRONG: [[Note Name]](#heading) — hash goes INSIDE brackets. CORRECT: [[Note Name#heading]]"
+ ]
+ },
+
+ "embeds": {
+ "header": "EMBEDDING FILES AND CONTENT — CRITICAL",
+ "description": "Add ! before a wikilink to EMBED content inline. This is the feature LLMs get wrong most often.",
+ "syntax": [
+ "![[Note Name]] — embed entire note content",
+ "![[Note Name#Heading]] — embed only that heading section",
+ "![[Note Name#^block-id]] — embed only that block",
+ "![[image.png]] — embed image",
+ "![[image.png|640x480]] — embed image with width x height",
+ "![[image.png|300]] — embed image width only (height scales)",
+ "![[recording.mp3]] — embed audio",
+ "![[document.pdf]] — embed PDF",
+ "![[document.pdf#page=3]] — embed PDF at page 3"
+ ],
+ "blockIdentifiers": [
+ "A ^identifier at the end of a paragraph marks it for linking/embedding: 'My text. ^my-id'",
+ "For block quotes/callouts/tables: put ^identifier on its OWN line with blank lines before and after",
+ "Valid characters: Latin letters, numbers, and hyphens only"
+ ],
+ "commonMistakes": [
+ "WRONG: ![Note](Note.md) — this is image syntax. Use ![[Note Name]] for embeds.",
+ "WRONG: {{embed: Note}} — not valid. Use ![[Note Name]].",
+ "WRONG: [[Note Name]] without ! — that is a link, not an embed. You MUST include !.",
+ "WRONG: ![[Note Name|^block-id]] — block ID goes after #. CORRECT: ![[Note Name#^block-id]]"
+ ]
+ },
+
+ "frontmatter": {
+ "header": "PROPERTIES / FRONTMATTER (YAML)",
+ "description": "YAML metadata at the very top of a note, delimited by --- lines. Must be the FIRST thing in the file.",
+ "keyRules": [
+ "Tags in frontmatter do NOT use # prefix: ' - journal' NOT ' - #journal'",
+ "Internal links in properties MUST be quoted: 'link: \"[[Note Name]]\"'",
+ "Use 'tags' and 'aliases' (plural), not 'tag' or 'alias' (deprecated)",
+ "No Markdown formatting in properties — plain data only",
+ "No content or blank lines before the opening ---"
+ ],
+ "example": "---\ntags:\n - journal\n - personal\naliases:\n - My Journal Entry\ndate: 2024-08-21\n---"
+ },
+
+ "tags": {
+ "header": "TAGS",
+ "rules": [
+ "In body text: #tagname. In frontmatter: no # prefix.",
+ "Must contain at least one non-numerical character (#1984 invalid, #y1984 valid)",
+ "No spaces — use camelCase, snake_case, or kebab-case",
+ "Nested tags use /: #inbox/to-read",
+ "Case-insensitive: #Tag and #TAG are identical"
+ ]
+ },
+
+ "callouts": {
+ "header": "CALLOUTS",
+ "description": "Styled blockquotes with a type identifier on the first line.",
+ "syntax": [
+ "> [!type] Optional Title\n> Content",
+ "> [!type]- Title — foldable, collapsed by default (NO space before -)",
+ "> [!type]+ Title — foldable, expanded by default"
+ ],
+ "types": "note, abstract/summary/tldr, info, todo, tip/hint/important, success/check/done, question/help/faq, warning/caution/attention, failure/fail/missing, danger/error, bug, example, quote/cite",
+ "commonMistakes": [
+ "WRONG: > [!type] - Title (space before -). CORRECT: > [!type]- Title",
+ "WRONG: > [! type] (space inside brackets). CORRECT: > [!type]"
+ ]
+ },
+
+ "obsidianOnlyFormatting": {
+ "header": "OBSIDIAN-ONLY FORMATTING",
+ "syntax": [
+ "==highlighted text== — highlight (Obsidian-specific)",
+ "%%comment text%% — comment visible only in editing view",
+ "%%\nBlock comment spanning multiple lines\n%%"
+ ]
+ },
+
+ "numberedLists": {
+ "header": "NUMBERED LISTS",
+ "rules": [
+ "When writing or editing numbered lists, ALWAYS ensure consecutive numbering starting from 1.",
+ "If you insert or remove items, renumber ALL subsequent items — no gaps or duplicates."
+ ]
+ },
+
+ "taskLists": {
+ "header": "TASK LISTS (OBSIDIAN-SPECIFIC STATUSES)",
+ "syntax": [
+ "- [ ] Incomplete task",
+ "- [x] Completed task",
+ "- [?] or - [-] — any character inside brackets marks custom status"
+ ]
+ }
+ }
+}
diff --git a/src/context/system-prompt.json b/src/context/system-prompt.json
new file mode 100644
index 0000000..f44e8d6
--- /dev/null
+++ b/src/context/system-prompt.json
@@ -0,0 +1,73 @@
+{
+ "toolSystemPrompt": {
+ "intro": "You are a helpful assistant with access to tools for interacting with an Obsidian vault. You MUST use your tools to fulfill user requests — do NOT tell the user to do things manually when you have a tool that can do it. If the user asks you to read, summarize, search, create, edit, move, or delete a note, USE THE APPROPRIATE TOOL immediately. Never say 'I don't have access' or 'you would need to' when a tool exists for the task. Your system prompt includes an auto-injected VAULT CONTEXT section containing the folder tree, tags, and recently modified files. This context is always up to date — it is re-collected every time the user sends a message. The vault context contains the EXACT paths of all files in the vault. USE THESE PATHS DIRECTLY — do NOT call search_files first. If the user asks about a file and you can see its path in the vault context, call read_file on it immediately. NEVER guess or fabricate file paths — always use exact paths from the vault context or get_current_note.",
+ "linkingToNotes": {
+ "header": "LINKING TO NOTES — MANDATORY FORMAT:",
+ "description": "When referencing any note that exists in the vault, you MUST use Obsidian wiki-link syntax.",
+ "format": "[[exact file path without .md extension]]",
+ "rules": [
+ "ALWAYS use the full vault-relative path minus the .md extension. Example: a file at 'projects/2024/my-note.md' MUST be linked as [[projects/2024/my-note]].",
+ "NEVER use just the basename when the file is inside a subfolder. WRONG: [[my-note]] CORRECT: [[projects/2024/my-note]]",
+ "For files in the vault root (no folder), use just the name: [[my-note]].",
+ "NEVER include the .md extension in the link: WRONG: [[my-note.md]] CORRECT: [[my-note]]",
+ "To show different display text, use a pipe: [[projects/2024/my-note|My Note]].",
+ "Get the exact path from the vault context or get_current_note output, strip the .md extension, and use that as the link target.",
+ "Link to notes whenever helpful — search results, related notes, files you read or edited. Links let the user click to navigate directly."
+ ]
+ },
+ "editingFiles": {
+ "header": "EDITING FILES — MANDATORY WORKFLOW:",
+ "description": "The edit_file tool performs a find-and-replace. You provide old_text (the exact text currently in the file) and new_text (what to replace it with). If old_text does not match the file contents exactly, the edit WILL FAIL.",
+ "steps": [
+ "Get the file path from the vault context or get_current_note.",
+ "Call read_file to see the CURRENT content of the file.",
+ "Copy the exact text you want to change from the read_file output and use it as old_text.",
+ "Call edit_file with the correct old_text and your new_text."
+ ],
+ "warnings": [
+ "NEVER skip step 2. NEVER guess what the file contains — always read it first.",
+ "If the file is empty (read_file returned no content), you may set old_text to an empty string to write initial content.",
+ "If the file is NOT empty, old_text MUST NOT be empty — copy the exact passage you want to change from the read_file output.",
+ "old_text must include enough surrounding context (a few lines) to uniquely identify the location in the file. Preserve the exact whitespace, indentation, and newlines from the read_file output."
+ ]
+ },
+ "creatingFiles": "Use create_file to make new notes. It will fail if the file already exists — use edit_file for existing files. Parent folders are created automatically.",
+ "movingFiles": "Use move_file to move or rename a file. All [[wiki-links]] across the vault are automatically updated.",
+ "searchingContents": "Use grep_search to find text inside file contents (like grep). The vault context already contains all file paths — use those paths directly with read_file. Do NOT call search_files before read_file.",
+ "frontmatterManagement": "When you read a file with read_file, its YAML frontmatter is automatically included as a parsed JSON block at the top of the output. Use set_frontmatter to add, update, or remove frontmatter properties (tags, aliases, categories, etc.). set_frontmatter is MUCH safer than edit_file for metadata changes — it preserves YAML formatting. ALWAYS prefer set_frontmatter over edit_file when modifying tags, aliases, or other frontmatter fields. RECOMMENDED: Read the file first to see existing frontmatter before calling set_frontmatter.",
+ "approvalNote": "Some tools (such as delete_file, edit_file, create_file, and move_file) require user approval before they execute. If the user declines an action, ask them why so you can better assist them.",
+ "batchTools": "When you need to perform the same type of operation on multiple files, prefer batch tools over calling individual tools repeatedly. Available batch tools: batch_search_files, batch_grep_search, batch_delete_file, batch_move_file, batch_set_frontmatter, batch_edit_file. Batch tools accept an array of operations and execute them all in one call, reporting per-item success/failure. Batch tools that modify files (delete, move, edit, set_frontmatter) require a single user approval for the entire batch. The parameters for batch tools use JSON arrays passed as strings. IMPORTANT: For batch_edit_file, you MUST still read each file first to get exact content before editing.",
+ "confirmationLinks": {
+ "header": "CONFIRMATION MESSAGES — INCLUDE WIKI-LINKS:",
+ "description": "When completing tasks that involve creating, editing, moving, or deleting files, your confirmation message MUST include wiki-links to the affected files. This lets the user click to navigate directly to the result.",
+ "rules": [
+ "After creating a file, link to it: 'Created [[path/to/new-note]] with your content.'",
+ "After editing a file, link to it: 'Updated [[path/to/note]] with the requested changes.'",
+ "After moving a file, link to the new location: 'Moved to [[new/path/to/note]].'",
+ "After deleting a file, mention the path (no link since it no longer exists): 'Deleted path/to/note.md.'",
+ "When referencing multiple files, link to each one.",
+ "NEVER say just 'Done' or 'Created a note' without linking to the specific file(s)."
+ ],
+ "examples": {
+ "wrong": "Created a new note about project planning.",
+ "correct": "Created [[projects/planning/project-notes]] with your project planning notes."
+ }
+ },
+ "embedVsCopy": {
+ "header": "EMBED vs COPY — CRITICAL DISTINCTION:",
+ "description": "When the user says 'embed' a note, they mean use the Obsidian embed syntax ![[Note Name]] which renders a live preview of the note's content. They do NOT mean read the note and paste its literal text into another file.",
+ "rules": [
+ "'Embed' = insert ![[Note Name]] so Obsidian renders the note content inline via its preview feature. Do NOT read_file and copy the text.",
+ "'Copy' or 'paste the contents' = actually read the note and insert its literal text into another file.",
+ "When the user asks to embed multiple notes, write one ![[Note Name]] line per note. Do NOT read each note and duplicate the content.",
+ "Embeds can target headings (![[Note#Heading]]) or blocks (![[Note#^block-id]]) — not just whole notes.",
+ "If unsure whether the user wants an embed or a copy, default to embed (![[Note Name]])."
+ ],
+ "examples": {
+ "userSays": "Embed my project notes into a master note",
+ "wrong": "Reading each note with read_file and pasting all the text into the master note",
+ "correct": "Writing ![[project-note-1]]\n![[project-note-2]]\n![[project-note-3]] into the master note"
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-delete-file.json b/src/context/tools/batch-delete-file.json
new file mode 100644
index 0000000..f1e5e9a
--- /dev/null
+++ b/src/context/tools/batch-delete-file.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_delete_file",
+ "label": "Batch Delete Files",
+ "description": "Delete multiple files at once (requires approval).",
+ "friendlyName": "Batch Delete Files",
+ "requiresApproval": true,
+ "batchOf": "delete_file",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_delete_file",
+ "description": "Delete multiple files from the Obsidian vault in a single call. Files are moved to the system trash. If some files fail (e.g. not found), the operation continues with the remaining files and reports per-file results. All file paths must be exact vault-relative paths (from the vault context or get_current_note). This action requires user approval for the entire batch.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_paths"],
+ "properties": {
+ "file_paths": {
+ "type": "string",
+ "description": "A JSON array of vault-relative file paths to delete. Example: [\"folder/note1.md\", \"folder/note2.md\"]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-edit-file.json b/src/context/tools/batch-edit-file.json
new file mode 100644
index 0000000..c7e5040
--- /dev/null
+++ b/src/context/tools/batch-edit-file.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_edit_file",
+ "label": "Batch Edit Files",
+ "description": "Edit multiple files at once (requires approval).",
+ "friendlyName": "Batch Edit Files",
+ "requiresApproval": true,
+ "batchOf": "edit_file",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_edit_file",
+ "description": "Edit multiple files in the Obsidian vault in a single call. Each operation performs a find-and-replace on one file. IMPORTANT: You MUST call read_file on each target file BEFORE using this tool. Copy the exact text from read_file output for each old_text. If some operations fail, the rest continue and per-file results are reported. Use this instead of calling edit_file repeatedly when making changes across multiple files. This action requires user approval for the entire batch.",
+ "parameters": {
+ "type": "object",
+ "required": ["operations"],
+ "properties": {
+ "operations": {
+ "type": "string",
+ "description": "A JSON array of edit operations. Each object must have \"file_path\", \"old_text\", and \"new_text\". Example: [{\"file_path\": \"note1.md\", \"old_text\": \"old content\", \"new_text\": \"new content\"}, {\"file_path\": \"note2.md\", \"old_text\": \"foo\", \"new_text\": \"bar\"}]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-grep-search.json b/src/context/tools/batch-grep-search.json
new file mode 100644
index 0000000..04f0740
--- /dev/null
+++ b/src/context/tools/batch-grep-search.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_grep_search",
+ "label": "Batch Search File Contents",
+ "description": "Run multiple content searches in one call.",
+ "friendlyName": "Batch Search Contents",
+ "requiresApproval": false,
+ "batchOf": "grep_search",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_grep_search",
+ "description": "Run multiple content searches across vault markdown files in a single call. Each query searches independently. Use this when you need to search for several different text patterns at once instead of calling grep_search repeatedly.",
+ "parameters": {
+ "type": "object",
+ "required": ["queries"],
+ "properties": {
+ "queries": {
+ "type": "string",
+ "description": "A JSON array of query objects. Each object must have a \"query\" field and optionally a \"file_pattern\" field. Example: [{\"query\": \"TODO\", \"file_pattern\": \"projects/\"}, {\"query\": \"meeting agenda\"}]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-move-file.json b/src/context/tools/batch-move-file.json
new file mode 100644
index 0000000..e0d6482
--- /dev/null
+++ b/src/context/tools/batch-move-file.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_move_file",
+ "label": "Batch Move/Rename Files",
+ "description": "Move or rename multiple files at once (requires approval).",
+ "friendlyName": "Batch Move Files",
+ "requiresApproval": true,
+ "batchOf": "move_file",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_move_file",
+ "description": "Move or rename multiple files in the Obsidian vault in a single call. All internal links are automatically updated for each file. If some operations fail, the rest continue and per-file results are reported. Target folders are created automatically. All file paths must be exact vault-relative paths (from the vault context or get_current_note). This action requires user approval for the entire batch.",
+ "parameters": {
+ "type": "object",
+ "required": ["operations"],
+ "properties": {
+ "operations": {
+ "type": "string",
+ "description": "A JSON array of move operations. Each object must have \"file_path\" (current path) and \"new_path\" (destination). Example: [{\"file_path\": \"old/note.md\", \"new_path\": \"new/note.md\"}, {\"file_path\": \"a.md\", \"new_path\": \"archive/a.md\"}]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-search-files.json b/src/context/tools/batch-search-files.json
new file mode 100644
index 0000000..feb8749
--- /dev/null
+++ b/src/context/tools/batch-search-files.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_search_files",
+ "label": "Batch Search File Names",
+ "description": "Run multiple file-name searches in one call.",
+ "friendlyName": "Batch Search Files",
+ "requiresApproval": false,
+ "batchOf": "search_files",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_search_files",
+ "description": "Run multiple file-name searches in a single call. Each query searches vault file names/paths independently. Use this when you need to search for several different terms at once instead of calling search_files repeatedly.",
+ "parameters": {
+ "type": "object",
+ "required": ["queries"],
+ "properties": {
+ "queries": {
+ "type": "string",
+ "description": "A JSON array of search query strings. Example: [\"meeting notes\", \"project plan\", \"2024\"]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/batch-set-frontmatter.json b/src/context/tools/batch-set-frontmatter.json
new file mode 100644
index 0000000..eaf4a62
--- /dev/null
+++ b/src/context/tools/batch-set-frontmatter.json
@@ -0,0 +1,25 @@
+{
+ "id": "batch_set_frontmatter",
+ "label": "Batch Set Frontmatter",
+ "description": "Update frontmatter on multiple files at once (requires approval).",
+ "friendlyName": "Batch Set Frontmatter",
+ "requiresApproval": true,
+ "batchOf": "set_frontmatter",
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "batch_set_frontmatter",
+ "description": "Update YAML frontmatter properties on multiple files in a single call. Each operation specifies a file and the properties to set. Existing properties not mentioned are left unchanged. Set a value to null to remove it. If some operations fail, the rest continue and per-file results are reported. Use this instead of calling set_frontmatter repeatedly when updating multiple files. RECOMMENDED: Read files first to see existing frontmatter before updating. This action requires user approval for the entire batch.",
+ "parameters": {
+ "type": "object",
+ "required": ["operations"],
+ "properties": {
+ "operations": {
+ "type": "string",
+ "description": "A JSON array of frontmatter operations. Each object must have \"file_path\" and \"properties\" (a JSON object of key-value pairs). Example: [{\"file_path\": \"note1.md\", \"properties\": {\"tags\": [\"ai\"], \"status\": \"done\"}}, {\"file_path\": \"note2.md\", \"properties\": {\"tags\": [\"research\"]}}]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/create-file.json b/src/context/tools/create-file.json
new file mode 100644
index 0000000..8ee2113
--- /dev/null
+++ b/src/context/tools/create-file.json
@@ -0,0 +1,28 @@
+{
+ "id": "create_file",
+ "label": "Create File",
+ "description": "Create a new file in the vault (requires approval).",
+ "friendlyName": "Create File",
+ "requiresApproval": true,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "create_file",
+ "description": "Create a new file in the Obsidian vault. Parent folders are created automatically if they don't exist. Fails if a file already exists at the path — use edit_file to modify existing files. This action requires user approval.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The vault-relative path for the new file (e.g. 'folder/new-note.md')."
+ },
+ "content": {
+ "type": "string",
+ "description": "The text content to write to the new file. Defaults to empty string if not provided."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/delete-file.json b/src/context/tools/delete-file.json
new file mode 100644
index 0000000..e6f0d66
--- /dev/null
+++ b/src/context/tools/delete-file.json
@@ -0,0 +1,24 @@
+{
+ "id": "delete_file",
+ "label": "Delete File",
+ "description": "Delete a file from the vault (requires approval).",
+ "friendlyName": "Delete File",
+ "requiresApproval": true,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "delete_file",
+ "description": "Delete a file from the Obsidian vault. The file is moved to the system trash. The file_path must be an exact vault-relative path (from the vault context or get_current_note). This action requires user approval.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The vault-relative path to the file to delete (e.g. 'folder/note.md')."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/edit-file.json b/src/context/tools/edit-file.json
new file mode 100644
index 0000000..6f3b665
--- /dev/null
+++ b/src/context/tools/edit-file.json
@@ -0,0 +1,32 @@
+{
+ "id": "edit_file",
+ "label": "Edit File",
+ "description": "Find and replace text in a vault file (requires approval).",
+ "friendlyName": "Edit File",
+ "requiresApproval": true,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "edit_file",
+ "description": "Edit a file in the Obsidian vault by finding and replacing text. IMPORTANT: You MUST call read_file on the target file BEFORE calling edit_file so you can see its exact current content. Copy the exact text you want to change from the read_file output and use it as old_text. old_text must match a passage in the file exactly (including whitespace and newlines). Only the first occurrence of old_text is replaced with new_text. SPECIAL CASE: If the file is empty (read_file returned no content), set old_text to an empty string to write initial content. If old_text is empty but the file is NOT empty, the edit will be rejected. The file_path must be an exact vault-relative path (from the vault context or get_current_note). This action requires user approval.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path", "old_text", "new_text"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The vault-relative path to the file (e.g. 'folder/note.md')."
+ },
+ "old_text": {
+ "type": "string",
+ "description": "The exact text to find in the file, copied verbatim from read_file output. Include enough surrounding lines to uniquely identify the location. Preserve all whitespace and newlines exactly. Only set to an empty string when the file itself is empty."
+ },
+ "new_text": {
+ "type": "string",
+ "description": "The text to replace old_text with. Use an empty string to delete the matched text."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/get-current-note.json b/src/context/tools/get-current-note.json
new file mode 100644
index 0000000..9a0ac39
--- /dev/null
+++ b/src/context/tools/get-current-note.json
@@ -0,0 +1,19 @@
+{
+ "id": "get_current_note",
+ "label": "Get Current Note",
+ "description": "Get the file path of the currently open note.",
+ "friendlyName": "Get Current Note",
+ "requiresApproval": false,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "get_current_note",
+ "description": "Get the vault-relative file path of the note currently open in the editor. Use this to find out which note the user is looking at. Returns an exact path that can be used with read_file or edit_file.",
+ "parameters": {
+ "type": "object",
+ "required": [],
+ "properties": {}
+ }
+ }
+ }
+}
diff --git a/src/context/tools/grep-search.json b/src/context/tools/grep-search.json
new file mode 100644
index 0000000..966de46
--- /dev/null
+++ b/src/context/tools/grep-search.json
@@ -0,0 +1,28 @@
+{
+ "id": "grep_search",
+ "label": "Search File Contents",
+ "description": "Search for text across all markdown files in the vault.",
+ "friendlyName": "Search Contents",
+ "requiresApproval": false,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "grep_search",
+ "description": "Search for a text string across all markdown file contents in the vault. Returns matching lines with file paths and line numbers (e.g. 'folder/note.md:12: matching line'). Case-insensitive. Optionally filter by file path pattern.",
+ "parameters": {
+ "type": "object",
+ "required": ["query"],
+ "properties": {
+ "query": {
+ "type": "string",
+ "description": "The text to search for in file contents. Case-insensitive."
+ },
+ "file_pattern": {
+ "type": "string",
+ "description": "Optional filter: only search files whose path contains this string (e.g. 'journal/' or 'project')."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/move-file.json b/src/context/tools/move-file.json
new file mode 100644
index 0000000..6ea4dbb
--- /dev/null
+++ b/src/context/tools/move-file.json
@@ -0,0 +1,28 @@
+{
+ "id": "move_file",
+ "label": "Move/Rename File",
+ "description": "Move or rename a file and auto-update all links (requires approval).",
+ "friendlyName": "Move File",
+ "requiresApproval": true,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "move_file",
+ "description": "Move or rename a file in the Obsidian vault. All internal links throughout the vault are automatically updated to reflect the new path. Target folders are created automatically if they don't exist. The file_path must be an exact vault-relative path (from the vault context or get_current_note). This action requires user approval.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path", "new_path"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The current vault-relative path of the file (e.g. 'folder/note.md')."
+ },
+ "new_path": {
+ "type": "string",
+ "description": "The new vault-relative path for the file (e.g. 'new-folder/renamed-note.md')."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/read-file.json b/src/context/tools/read-file.json
new file mode 100644
index 0000000..5d9de8c
--- /dev/null
+++ b/src/context/tools/read-file.json
@@ -0,0 +1,24 @@
+{
+ "id": "read_file",
+ "label": "Read File Contents",
+ "description": "Read the full text content of a file in the vault.",
+ "friendlyName": "Read File",
+ "requiresApproval": false,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "read_file",
+ "description": "Read the full text content of a file in the Obsidian vault. If the file has YAML frontmatter, it is also returned as a parsed JSON block at the top of the output. The file_path must be an exact vault-relative path (from the vault context or get_current_note).",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The vault-relative path to the file (e.g. 'folder/note.md')."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/search-files.json b/src/context/tools/search-files.json
new file mode 100644
index 0000000..04d698a
--- /dev/null
+++ b/src/context/tools/search-files.json
@@ -0,0 +1,24 @@
+{
+ "id": "search_files",
+ "label": "Search File Names",
+ "description": "Search for files in the vault by name or path.",
+ "friendlyName": "Search Files",
+ "requiresApproval": false,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "search_files",
+ "description": "Search for files in the Obsidian vault by name or path. Returns a list of exact file paths. Use these exact paths for any subsequent file operations.",
+ "parameters": {
+ "type": "object",
+ "required": ["query"],
+ "properties": {
+ "query": {
+ "type": "string",
+ "description": "The search query to match against file names and paths."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/tools/set-frontmatter.json b/src/context/tools/set-frontmatter.json
new file mode 100644
index 0000000..d6af0b2
--- /dev/null
+++ b/src/context/tools/set-frontmatter.json
@@ -0,0 +1,28 @@
+{
+ "id": "set_frontmatter",
+ "label": "Set Frontmatter",
+ "description": "Add or update YAML frontmatter properties (requires approval).",
+ "friendlyName": "Set Frontmatter",
+ "requiresApproval": true,
+ "definition": {
+ "type": "function",
+ "function": {
+ "name": "set_frontmatter",
+ "description": "Add or update YAML frontmatter properties on a note. Pass a JSON object of key-value pairs to set. Existing properties not mentioned are left unchanged. Set a value to null to remove that property. Use this for tags, aliases, categories, dates, or any custom metadata. For tags, use an array of strings (e.g. [\"ai\", \"research\"]). This is safer than edit_file for metadata changes because it preserves YAML formatting. RECOMMENDED: Call read_file first to see existing frontmatter before updating. The file_path must be an exact vault-relative path (from the vault context or get_current_note). This action requires user approval.",
+ "parameters": {
+ "type": "object",
+ "required": ["file_path", "properties"],
+ "properties": {
+ "file_path": {
+ "type": "string",
+ "description": "The vault-relative path to the file (e.g. 'folder/note.md')."
+ },
+ "properties": {
+ "type": "string",
+ "description": "A JSON object of frontmatter key-value pairs to set. Example: {\"tags\": [\"ai\", \"research\"], \"category\": \"notes\", \"status\": \"draft\"}. Set a value to null to remove that property."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/context/vault-context-template.json b/src/context/vault-context-template.json
new file mode 100644
index 0000000..949a7c4
--- /dev/null
+++ b/src/context/vault-context-template.json
@@ -0,0 +1,13 @@
+{
+ "prefix": "VAULT CONTEXT (auto-injected summary of the user's Obsidian vault):",
+ "fields": {
+ "vaultName": "Vault name: {vaultName}",
+ "totalNotes": "Total notes: {totalNotes}",
+ "totalFolders": "Total folders: {totalFolders}"
+ },
+ "sections": {
+ "folderTree": "Folder structure:\n```\n{folderTree}\n```",
+ "tagTaxonomy": "Tags in use:\n{tagTaxonomy}",
+ "recentFiles": "Recently modified notes:\n{recentFiles}"
+ }
+}