01Safety
0.0 / 30
What changed in the harness
Selection accuracy 100→96, token cost up 5%, unconfirmed writes 0%→0%.
Category breakdown
Earned points across the four signals Gradable measures. Safety and Legibility are scored out of 30; Economics and Discoverability are scored out of 20.
0.0 / 30
22.5 / 30
17.5 / 20
12.8 / 20
Highest-impact fix
Estimated gain +30 pointsExpose machine-readable principal/tenant confirmation and a non-mutating permission check so agents can verify both before destructive actions.
Description evidence
20 defects found across the exposed tool descriptions. Suggested rewrites make purpose, inputs, boundaries, and returns easier for an agent to understand.
| Tool | Defect types | Suggested rewrite |
|---|---|---|
bear_trash_note |
no_return_description |
Move a Bear note to the trash. This is a soft delete — the note can be recovered from Bear's trash. The note is identified by its ID. Returns the ID of the trashed note. |
bear_sync |
no_return_description |
Trigger a sync of Bear notes from iCloud. Normally an incremental sync fetching only changes; use 'full' to force a complete re-sync. Most read operations auto-sync when the cache is stale, so manual sync is rarely needed. Returns a summary of the sync result. |
bear_toggle_todo |
no_return_description |
Toggle a specific TODO item in a Bear note between complete and incomplete. The item_index is 1-based — use bear_get_todos first to see the list with index numbers. Returns the note ID and the new completion state of the toggled item. |
bear_attach_file |
no_return_description |
Attach a file or image to an existing Bear note. The file is uploaded to iCloud and embedded in the note's markdown. Supports common image formats (jpg, png, gif, webp, heic) and other file types (pdf, zip, etc.). By default the attachment is appended to the end. Use 'after' or 'before' to place it relative to text in the note, or 'prepend' to put it right after the title. Returns the note ID of the note the file was attached to. |
bear_archive_note |
no_return_description |
Archive a Bear note. Archived notes are hidden from the main list but not deleted. Use 'undo' to unarchive. Returns the note ID and whether the note is now archived. |
bear_add_tag |
no_return_description |
Add a tag to an existing Bear note. The tag is inserted into the note's markdown. Hierarchical tags like 'parent/child' also index every ancestor — so the note becomes discoverable under both #parent and #parent/child in Bear's sidebar. Returns the note ID and the note's updated tags. |
bear_remove_tag |
no_return_description |
Remove a tag from a specific Bear note. Works on any tag visible in 'tags' on the note — including ancestor tags like 'parent' that exist only as hierarchical expansions. Removing a hierarchical leaf like 'parent/child' also drops orphaned ancestors from the tag index. Returns the note ID and the note's updated tags. |
bear_rename_tag |
no_return_description |
Rename a tag across all Bear notes. Every note containing the old tag will be updated. Returns the number of notes updated and the old/new tag names. |
bear_delete_tag |
no_return_description |
Delete a tag from all Bear notes. The tag text is removed but notes are preserved. Returns the number of notes from which the tag was removed. |
bear_find_untagged |
no_return_description |
List Bear notes that have no tags assigned (untagged). Returns an array of untagged notes with their IDs, titles, tags, pin status, and modification dates. |
bear_context_setup |
no_return_description |
Initialize a context library — a curated, synced folder of Bear notes optimized for LLM consumption. Creates the directory structure and config. After setup, tag Bear notes with #context (or a custom prefix) and use bear_context_sync to pull them in. One-time operation. Returns the path of the created context directory along with its configuration. |
bear_context_sync |
no_return_description |
Sync qualifying Bear notes to the local context library. Adds new notes, updates changed notes, and removes notes that no longer qualify (tag removed, trashed, etc.). Regenerates the index. Only touches the bear/ directory — external/ and inbox/ are untouched. Call this when the user asks to sync, refresh, or update their context. Returns a summary of notes added, updated, and removed. |
bear_context_fetch |
no_return_description |
Load the full content of specific files from the context library. Pass relative paths like 'bear/arch-overview.md' or 'external/jira-ticket.md'. Use after reading the index to load only relevant files — never load everything. Returns the full markdown content of each requested file. |
bear_context_add |
no_return_description |
Add a Bear note to the context library by tagging it with #context. Optionally specify a subtag for grouping (e.g., subtag 'jira' → #context/jira). Triggers a sync after tagging and returns confirmation of the tag and sync result, or an error if the note could not be tagged. |
bear_context_remove |
no_return_description |
Remove a Bear note from the context library by removing its #context tag. Triggers a sync to delete the local file and returns confirmation of the removal, or an error if the note was not found. |
bear_context_import |
no_return_description |
Import external content into the context library. Content is written to the external/ directory with YAML front matter (source, group, summary, date). Use this to add non-Bear content like Jira tickets, Slack threads, API docs, or any markdown. The content is passed via stdin and a filename must be provided. Returns confirmation of the saved file and its metadata, or an error if the import failed. |
bear_context_triage |
no_return_description |
Triage a file in the inbox. Three actions: 'keep' moves it to external/ with optional group/summary metadata. 'push_to_bear' creates a Bear note tagged #context (+ optional subtag) and deletes the inbox file. 'discard' deletes the file. All actions regenerate the index and return the outcome of the triage (file destination or deletion) and any errors. |
bear_context_push_to_bear |
no_return_description |
Push an external file to Bear as a new note. Creates a Bear note from the file content, tags it with #context (+ optional subtag), and removes the original external file. Returns confirmation of the created note (including the note title or ID), or an error if the push failed. Use when external content has matured enough to become a permanent Bear note. |
bear_context_set_prefix |
no_return_description |
Change the context library's tag prefix and re-tag every Bear note that currently uses the old prefix. Sub-tags are preserved — `#context/research` becomes `#<new>/research`. Updates both the markdown body and the CloudKit tag index, and persists the new prefix to the context config. Returns the number of notes re-tagged and a confirmation, or an error. Useful when aligning the qualifier tag with a broader naming scheme like Johnny Decimal (e.g. '10-projects'). Run `bear_context_sync` afterwards to refresh the library. |
bear_context_remove_external |
no_return_description |
Remove a file from the external/ directory in the context library. Deletes the file and regenerates the index. Returns confirmation of the deletion, or an error if the file does not exist. Use when external content is no longer needed. |
Selection evidence
11 pairs where similar names or overlapping descriptions may send an agent toward the wrong tool.
| Tool A | Tool B | Confidence | Why they collide |
|---|---|---|---|
bear_context_remove |
bear_context_remove_external |
medium | Both tools remove content from the context library and differ only by source — bear_context_remove deletes a Bear note (via id) while bear_context_remove_external deletes an external/ file. A task like 'remove that doc from my context' doesn't reveal whether the item is a Bear note or an external file, so a wrong pick is plausible. |
bear_search |
bear_context_search |
medium | The context library contains Bear notes, so a request like 'search my notes for X' or 'find X in my context' could route to either the iCloud search or the context-library search. The phrasing 'search my context' vs 'search my notes' is not reliably distinguished by users. |
bear_sync |
bear_context_sync |
medium | Plain 'sync' tasks are ambiguous: bear_sync pulls Bear notes from iCloud, while bear_context_sync is documented to be called whenever the user asks to 'sync, refresh, or update their context'. A bare 'sync my notes' could target either the iCloud cache or the local context library. |
bear_context_add |
bear_context_import |
medium | Both add content to the context library: add tags an existing Bear note with #context, while import writes external content to external/. 'Add this to my context' doesn't state whether the source is a Bear note or foreign content, making the correct tool selection ambiguous. |
bear_context_add |
bear_context_push_to_bear |
low | A request like 'add this note/context to Bear' could mean tagging an existing Bear note (bear_context_add, needs an id) or converting an external file into a Bear note (bear_context_push_to_bear, needs a filename). The overlap is real but the differing input types usually disambiguate. |
bear_context_import |
bear_context_ingest |
medium | 'Import' and 'ingest' are near-synonyms, and a task like 'ingest this content into context' could wrongly route to bear_context_ingest, which only scans the inbox and never accepts content, instead of bear_context_import which actually writes the provided content to external/. |
bear_context_import |
bear_context_push_to_bear |
medium | A task like 'import this Jira ticket into my notes/context' is ambiguous about the destination: import writes it to external/, whereas push_to_bear turns an external file into a permanent #context Bear note. Agents could pick the wrong write operation for external content. |
bear_context_fetch |
bear_context_import |
low | 'Pull this content into context' could mean either loading an existing library file (fetch) or adding new external content (import). Whether the content already lives in the library is often unclear from the request, though the tools' read-vs-write nature usually steers correctly. |
bear_list_todos |
bear_get_todos |
medium | 'Show me my todos' is ambiguous about granularity: bear_list_todos returns notes containing incomplete items (with counts only), while bear_get_todos returns the actual items for a specific note. With no note id in the request, an agent may pick the wrong one and return counts instead of the items themselves. |
bear_remove_tag |
bear_delete_tag |
medium | 'Remove tag X' vs 'delete tag X' use near-synonym verbs, but remove applies to a single note (requires an id) while delete removes the tag from all notes globally. A user task that doesn't specify scope can plausibly be routed to the wrong tool. |
bear_add_tag |
bear_context_add |
low | bear_context_add is effectively implemented by tagging a note with #context, so 'add this note to my context' overlaps with regular tag-add behavior. An agent could pick bear_add_tag with tag='context' and miss the automatic sync, or pick bear_context_add for what was really a plain tag request. |
Compare the field