Skip to content

fix(tools): reword the edit tools' empty-line rule and correct nine tool descriptions - #678

Merged
aliasunder merged 20 commits into
mainfrom
fix/tool-description-wording
Oct 19, 2026
Merged

aliasunder merged 20 commits into
mainfrom
fix/tool-description-wording

Conversation

@aliasunder

@aliasunder aliasunder commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

Wording-only changes to nine MCP tool definitions. The main change rewrites the empty-line rule in the three line-editing tools by its outcome: blank lines never double, and to remove a table row with vault_replace_in_note, include its line break. Each rule now has one worked example. The other changes correct descriptions that said less than, or something different from, what the server does. No tool behaviour changes.

Changes by tool

  • vault_replace_in_note, vault_delete_span, vault_replace_span — empty-line rule restated by outcome, with the end-of-note case shown ("A\n\nB\n" without "B" → "A\n"), and a plain closing sentence: empty lines elsewhere in the note stay as they are, and a line holding only spaces or tabs counts as text. Every claim was checked against vault-patcher.ts with probes. Other changes:
    • vault_replace_span's Parameters list now mirrors vault_delete_span's.
    • vault_delete_span's Returns quotes its real message.
    • vault_replace_in_note gains a replace_all_occurrences example.
    • "Case-sensitive" moves from the span tools' openings into end_anchor's schema, beside start_anchor's.
    • The duplicate "Operates on the body only" sentence is cut from these three and from vault_insert_at_anchor; each opening already says the edit is in the note's body.
    • Schema text that repeated the descriptions is cut.
  • vault_patch_note:
    • An append lands below a section's trailing empty lines, so a row appended after a table and a blank line starts a new table; it points to vault_insert_at_anchor for extending a table.
    • Every operation writes content as whole lines with no separator.
    • To empty a section, use vault_delete_span.
  • vault_search:
    • The related filter takes the value exactly as written in the note's property, brackets and alias included.
    • type matches case-sensitively.
    • File content (canvas, PDF, text) is mentioned only while FILE_TOOLS_ENABLED is on, and any filter other than folder limits results to notes.
    • The checkbox and time-zone sentences are rewritten so a reader can follow them, and the keyword-only text says a higher score is more relevant.
    • "Falls back to keyword-only ranking before any embeddings exist" corrects "while embeddings are being built"; the vector leg returns hits as soon as any vector exists.
    • The two description variants now share their common parts.
  • vault_get_outgoing_links — lists embeds and frontmatter links, as vault_get_backlinks does. Each existing target appears once. A broken one appears once per target text, which is its path: the text before any #heading or |alias, letter case kept, with a markdown link's %-escapes decoded. Broken links report kind "note", and canvas text-card links are not reported.
  • vault_read_file:
    • Three Errors entries gain a remedy.
    • The .md and directory cases quote the real messages.
    • Facts stated more than once are cut to one place each, including the raw file-type mapping and "1-based".
  • vault_update_task — the no-block_id sentence now covers only Kanban sub-tasks the server created. The recurring-spawn placement, done lane, omitted position, and invalid date entries are reworded to match the code. The recurrence and on_completion schemas no longer repeat the status side effects the description lists.
  • vault_insert_at_anchor — the opening says the line is in a note's body, and drops sentences its schemas and Errors already carry. The properties sentence now matches its four siblings ("saving may rewrite their YAML in block style"), and Returns says N counts content's line breaks plus one.
  • Filesystem errors — the two ENAMETOOLONG and EACCES bullets become one grouped bullet (describeFilesystemErrorEntry in tool-helpers.ts) that names each remedy. It names vault_move_note for the rename only while that tool is served. AGENTS.md's Errors rule now allows a grouped bullet for errors of one class with short remedies. vault_patch_note, vault_update_task and vault_insert_at_anchor gain the bullet: the comment on the constant asks each saving tool to list it once its description is revised, and all three were revised here. Six tools carry the bullet, and all six are among this PR's edited tools, so it re-grades no other tool: vault_patch_note, vault_replace_in_note, vault_delete_span, vault_replace_span, vault_insert_at_anchor and vault_update_task.

Removed text, each repeated elsewhere in the same tool or its schema:

  • "position-aware score blending" and the FTS5/BM25/porter terms in vault_search; the caller can't act on them.
  • vault_search's "narrow by metadata, search by text" phrase and its opening "Combine a text query with structured filters…" sentence; the Filters lead-in and When to use carry both.
  • vault_search's properties bullet's restatement of its schema.
  • The anchor-fragment advice in both span tools' When to use, which their anchor schemas give.
  • "(never cuts mid-line)" in both span tools, which their opening sentences say.
  • vault_read_file's "Richer than flat text extraction" sentence and its example's metadata-line gloss; the list above it and the Line paging paragraph carry both.

Size

The default tool list goes from 140,984 to 141,568 characters (+584). Per tool, measured as description plus JSON input schema:

Tool Before After Change
vault_patch_note 6,063 6,710 +647
vault_update_task 16,002 16,333 +331
vault_insert_at_anchor 3,716 3,984 +268
vault_get_outgoing_links 2,193 2,441 +248
vault_replace_in_note 4,519 4,450 -69
vault_read_file 7,031 6,905 -126
vault_search 6,315 6,153 -162
vault_replace_span 5,318 5,104 -214
vault_delete_span 4,693 4,354 -339
Default list (33 tools) 140,984 141,568 +584

The three new filesystem-error listings add about 1,200 characters. The rest of the PR, including the grouped bullet's savings in the three tools that already carried it, saves about 615.

Proposed new baseline: CHARS_PER_TOOL_ALLOWANCE 4,273 → 4,290. Glama's quality grader credits a complete error list with remedies under Behavior. The rule on describeFilesystemErrorEntry in tool-helpers.ts adds that bullet as each saving tool's description is revised. So 4,290 is the proposed allowance for descriptions written to the grader's rubric, not slack. The default list averages 4,290 per tool, 2 characters under the new cap, and the embedding-off list is 1,000 under.

Review

  • ship-check Phases 1–5 ran on the branch:
    • PR review fixed 1 finding.
    • A fresh-eyes read as an integrating developer raised the pauses that the code-quality pass resolved (37 fixes).
    • The test audit added 7 tests: the gated vault_patch_note advice, and the FILE_TOOLS_ENABLED wording in both vault_search variants.
    • The bug check fixed 2 description-versus-code mismatches.
  • Tool-definition reviewer: a first review over every changed configuration, then re-reviews over each later commit, the grouped bullet and the final wording round included. No unintended text changes and no dropped facts. Every defect is fixed or dismissed with a reason: rare server-fault errors with no caller remedy, and pre-existing wording outside this change, recorded for a later round.
  • npm test on the head rebased onto main: 5,363 passed, 2 skipped. The tool-surface snapshot is regenerated, and the build, lint and knip are clean.

Live Test Results

Head: b7cbcde

The current head, f22a3ec, differs from the tested head in tool description and schema text, the size allowance, and a rebase onto main; this PR changes no server behaviour. The tool-surface snapshot test in CI checks the served text.

  • Test image: Test Deploy run 38979883718 built org.opencontainers.image.revision=b7cbcde3635ba6f46a5263af4f7b8d823b838845. Its log shows the container Recreated, Started and Healthy. On the host, the running container is ghcr.io/aliasunder/vault-cortex:test, image sha256:033ddc291227…, revision label b7cbcde3635ba6f46a5263af4f7b8d823b838845, started 2026-10-16 23:12:56 UTC.
  • Released image (before): ghcr.io/aliasunder/vault-cortex:remote v0.54.14, image sha256:d8c09778d068…, revision label aa361ed4540872cc997ed0c0416210f61a867f5b.
  • Served tool list: tools/list inside the test container returns 33 tools. Every description matches the committed obsidian-sync.json snapshot character for character, and every input schema matches with key order normalized.
  • Behaviour the new descriptions state: the probes ran on the released image, then on the test image, through the deployed /mcp endpoint, each on its own new note. Results were identical on both images, since this PR changes no behaviour, and each matches what the new text says. All probe notes were deleted afterwards.
Probe Description claim Result (both images)
1. vault_replace_in_note deleting B from A\n\nB\n at the note's end the run above counts one fewer: A\n A\n
2. vault_delete_span on a middle table row removing a table row leaves the table whole | a | b |, | --- | --- |, | 3 | 4 |, then a blank line and After
3. vault_replace_span of that row with "| X | Y |\n" content ending in a line break leaves an empty line after it, which splits a table | X | Y |, then an empty line, then | 3 | 4 |
4. vault_patch_note append of | 2 | to a section whose table ends in a blank line lands below the empty lines and starts a new table | 1 |, then an empty line, then | 2 |
5. vault_get_outgoing_links on a note linking [[Missing Note]] twice, [[missing note]], [[Missing Note#Heading|alias]], and an existing note twice each existing target listed once; a broken one, once per spelling 3 entries: Missing Note, missing note, and the existing note

Found and left out of this PR

  • On the last section of a note that ends in a line break, vault_patch_note's append inserts a blank line before the content. The description states only the mid-note case.
  • A text file or canvas that starts with a UTF-8 byte-order mark: vault_read_file strips the mark, and the canvas is left out of the search index.
  • A vault_search query containing a control character fails on the file-content leg with an FTS5 syntax error.

🤖 Generated with Claude Code

Comment thread src/vault-mcp/mcp-core/tools/search-tools.ts
Comment thread src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts
Comment thread src/vault-mcp/mcp-core/__tests__/tool-surface-snapshot.test.ts Outdated
Comment thread src/vault-mcp/mcp-core/tools/asset-tools.ts Outdated
Comment thread src/vault-mcp/mcp-core/tools/vault-crud-tools.ts
@umm-actually

umm-actually Bot commented Oct 16, 2026

Copy link
Copy Markdown

Shed vault_get_backlinks' duplicated path facts like its sibling
Low severity · conventions · high confidence

src/vault-mcp/mcp-core/tools/search-tools.ts:565 — beyond the diff's line ranges, in code the changes touch or depend on.

Pre-existing: vault_get_backlinks' Parameters line restates the path facts its own schema already carries ('Exact vault-relative path including .md or .canvas extension … Case-sensitive.'), the exact duplication this PR just removed from vault_get_outgoing_links' Parameters line. The AGENTS.md split rule gives the schema the format facts and reserves description space for what it doesn't say.

Failure scenario: State: a later edit changes the matching rule in one of the two copies — the schema's 'Case-sensitive.' versus the description's restated line — and clients reading both receive contradictory matching rules while the description's size budget pays twice for one fact.

Suggested fix
In the next wording pass over vault_get_backlinks (per the grader rule that only revised tools change), drop the Parameters line's format facts the schema states — here the whole line, as vault_get_outgoing_links now does — leaving the schema's text as the single home for extension and case-sensitivity.

umm-actually · z-ai/glm-5.3-flash

@umm-actually

umm-actually Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

umm-actually re-reviewed at f22a3ec

No new findings (11 tracked finding(s) across all runs).

Context notes
  • 18 changed file(s) excluded from review: src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/default.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/disabled-tools.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/file-tools-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/file-tools-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/memory-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/memory-off+file-tools-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/memory-off+file-tools-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/memory-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/obsidian-sync.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+file-tools-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+file-tools-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+memory-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+memory-off+file-tools-off+embedding-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+memory-off+file-tools-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly+memory-off.json (diff_exclude_paths input), src/vault-mcp/mcp-core/__tests__/__snapshots__/tool-surface/readonly.json (diff_exclude_paths input)

umm-actually · z-ai/glm-5.3-flash

@aliasunder

Copy link
Copy Markdown
Owner Author

Response to umm-actually comment 6221394911 (vault_get_backlinks' Parameters line restates its path schema): valid. The maintainer approved recording the one-line cut for the next description round, since vault_get_backlinks scores 5.0 and any edit re-grades it.


🔍 ship-check · pr-monitor · claude-opus-5-5

Comment thread src/vault-mcp/mcp-core/tools/vault-crud-tools.ts Outdated
Comment thread src/vault-mcp/mcp-core/tools/vault-crud-tools.ts Outdated
Comment thread src/vault-mcp/mcp-core/tools/search-tools.ts
Comment thread src/vault-mcp/mcp-core/__tests__/tool-surface-snapshot.test.ts Outdated
Comment thread src/vault-mcp/mcp-core/tools/asset-tools.ts
@aliasunder
aliasunder force-pushed the fix/tool-description-wording branch from bd6964a to b7cbcde Compare October 16, 2026 22:50
aliasunder and others added 20 commits October 16, 2026 21:31
…, link and file descriptions

- vault_replace_in_note, vault_delete_span, vault_replace_span: state the
  empty-line rule by its outcome (blank lines never double; include the line
  break to remove a table row), mirror the span tools' Parameters lists, quote
  vault_delete_span's message, and drop schema text the descriptions repeat.
- vault_patch_note: an append lands below the section's trailing empty lines.
- vault_search: give the related filter's value format, say type matches
  case-sensitively, mention file content only while file tools are on, and
  cut repeated or undefined phrases.
- vault_get_outgoing_links: list embeds and frontmatter links.
- vault_read_file: give remedies for three errors; cut two repeated facts.
- vault_update_task: scope the no-block_id sentence to sub-tasks the server
  creates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and correct replace_span's trailing-newline wording

An append at the end of a note lands after the note's final line break, so a row appended to a table that ends the note starts a new table. A trailing newline in replace_span content leaves an empty line after the block rather than always adding one.

Ship-Check: pr-review · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The end-of-note blank line is a defect tracked separately; the
vault_insert_at_anchor remedy already covers both cases.

Ship-Check: triage · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A cold read still stopped on "a line it empties" and "one fewer at the
end of the note". Split deletions that leave text on their line from those
that empty it, and show the end-of-note case.

Ship-Check: triage · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vault_search's description parts

Answers points a first-time reader stopped on: what a broken outgoing
link's kind and title are, which time zone date filters use, how true and
1 match a checkbox, where a recurring task's spawn and nested lines go,
what an omitted position does, and why a .tmp name must shrink by 41
bytes. Cuts restated text (the span tools' whole-line sentence, search
implementation names, a duplicated search_mode explanation) to stay
within the tool-surface size cap. Both vault_search variants now build
from shared parts so the shared facts change in one place.

Ship-Check: code-quality · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew operation advice

vault_search names file content, the extension field and file results only
while file tools are on; four cases cover both embedding variants.
vault_patch_note's append and replace lines drop their vault_insert_at_anchor
and vault_delete_span advice when those tools are disabled.

Ship-Check: test-audit · claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…search's keyword-only fallback

At the end of a note, the edit tools keep the note's own trailing empty lines, so the result is the wider run or one fewer, not always one fewer. vault_search ranks hybrid as soon as any embedding exists, so keyword-only ranking applies only before the first embeddings are built.

Ship-Check: bug-check · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… four siblings

The other four edit tools now say saving may rewrite properties' YAML in
block style; this is the last tool carrying the old "on first edit" wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- vault_patch_note, vault_update_task: list the filesystem errors, which
  tool-helpers.ts asks each saving tool to add when its description is
  revised.
- vault_search: say a filter other than folder limits results to notes,
  name the bound in the calendar-date entry, and say which score is better
  in the keyword-only text.
- vault_get_outgoing_links: each target is listed once; cut the path
  bullet's repeat of the schema.
- The edit tools' end-of-note clause names what counts one fewer.
- vault_replace_in_note: add a replace_all_occurrences example.
- Cut repeats of the schemas from vault_delete_span, vault_replace_span,
  vault_replace_in_note, vault_read_file and vault_update_task.

Raise CHARS_PER_TOOL_ALLOWANCE from 4,226 to 4,250: the two filesystem
entries add about 780 chars to the default list, which the cuts do not
cover.

Ship-Check: triage · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…schema repeats

- vault_insert_at_anchor: add the ENAMETOOLONG and EACCES entries, as
  tool-helpers.ts asks once a saving tool's description is revised.
- vault_search: cut the opening sentence the Filters lead-in and When to use
  repeat, and the properties bullet's restatement of its schema.
- vault_delete_span, vault_replace_span: cut "(never cuts mid-line)",
  which the opening already says.
- vault_replace_in_note: drop the gloss on the replace_all_occurrences
  example.

Set CHARS_PER_TOOL_ALLOWANCE to 4,256 for the net growth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and update the size-cap comment

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The six saving tools that list ENAMETOOLONG and EACCES now share one bullet
that names each remedy. AGENTS.md's Errors rule allows a grouped bullet for
errors of one class with short remedies. CHARS_PER_TOOL_ALLOWANCE drops to
4,245 for the shorter list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the filesystem bullet

The grouped bullet again says why a note that reads fine can fail to save,
and names the rename tool while it is served. FILESYSTEM_ERROR_ENTRY becomes
describeFilesystemErrorEntry so the tool name follows DISABLED_TOOLS.
CHARS_PER_TOOL_ALLOWANCE goes to 4,253 for the longer bullet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-entry helper

- The filesystem bullet says the message names the cause and usually the
  file: a write that fails on a full disk carries no path.
- vault_get_outgoing_links lists each existing target once; broken links
  keep their raw text, so one missing note can appear under several
  spellings.
- vault_insert_at_anchor's Returns says line(s), as the code does.
- describeFilesystemErrorEntry takes whenToolEnabledText and gates the
  rename tool itself; clearer comments and a search-tools const name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s lead

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's vault_read_note entries raised the default combo's total; the
default list now averages 4,260 characters per tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Say plainly that empty lines away from the edit stay as they are, in
  the three line-editing tools.
- Move "case-sensitive" into the span tools' end_anchor schema, and
  cut each edit tool's duplicate body-only sentence.
- Cut repeated text from vault_insert_at_anchor, vault_update_task's
  recurrence and on_completion schemas, and vault_read_file's raw and
  start_line text.
- Say what makes two broken links in vault_get_outgoing_links distinct.
- Set CHARS_PER_TOOL_ALLOWANCE to 4,250 for the smaller list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vault_get_outgoing_links stores a markdown link's target with its
%-escapes decoded, so a broken target's path is not always the text as
written. The default list grows to 4,251 characters per tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inks

The rebase onto main kept this PR's daily_note_forward_ref sentence,
which dropped main's condition that the flag is never set when the
daily notes folder setting is the vault root or blank. Restore it, and
set the allowance to 4,290 for the rebased list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aliasunder
aliasunder force-pushed the fix/tool-description-wording branch from 7402337 to f22a3ec Compare October 17, 2026 01:35
@aliasunder
aliasunder merged commit 8c2ccb2 into main Oct 19, 2026
18 checks passed
@aliasunder
aliasunder deleted the fix/tool-description-wording branch October 19, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant