Suggestion tools

~4 min read

Suggestion tools

Tools for agents to manage their own pending proposals and address mentions.

These are most useful for propose-only keys: their writes don’t commit, they queue as proposals for a human to accept or reject (see Suggestions mode/01 Overview). Both tools are scoped to read — they only touch the proposal store, never vault content — and both are filtered to the calling key’s own queue, so one agent can’t peek at or cancel another’s.

list_my_proposals

List the pending proposals authored by the calling key.

Input: none.

{}

Returns:

{
  "proposals": [
    {
      "id": "ab12cd34-...-uuid",
      "tool": "patch_section",
      "path": "Inbox/note.md",
      "operation": "patch",
      "timestamp": "2026-05-28T09:12:34Z"
    }
  ]
}

Each entry reports the tool that produced the proposal, the target path, the operation kind, and when it was filed. There is no server-side filter argument — filter client-side on the returned list if you need to.

withdraw_proposal

Cancel a pending proposal you authored. Refuses to touch other agents’ queues.

Input:

{"id": "ab12cd34-...-uuid"}

The id must be a lowercase UUID (the same value list_my_proposals returns); anything else is rejected before it reaches the store.

Returns:

{"ok": true, "id": "ab12cd34-...-uuid"}

ok is false if no matching proposal was found in your queue (already accepted/rejected, or never yours).

propose_batch

File several note writes as one reviewable batch — e.g. a multi-page ingest — so the user accepts or rejects the whole set together rather than approving pages one by one. Propose-only keys only (a commit key should just write each note directly). Each item is a write_note.

Input:

{
  "items": [
    {"path": "Pages/Vector databases.md", "content": "---\ntitle: ...\n---\n# ...", "mode": "create"},
    {"path": "Pages/Embeddings.md",       "content": "..."},
    {"path": "index.md",                  "content": "...", "mode": "append"}
  ]
}

mode is create (default) / overwrite / append / prepend. Every item’s path is checked against the key’s folder allowlist; if any is out of scope the whole batch is rejected and nothing is saved.

Returns:

{"status": "pending", "batchId": "ab12cd34-...", "proposalIds": ["...", "..."], "count": 3}

The proposals appear grouped under the batch in the proposals UI, with Accept all / Reject all. Accepting a batch applies its proposals in order; if one has gone stale meanwhile it’s reported and skipped while the rest still apply (a batch isn’t a single atomic transaction across files).

complete_directive

Mark a > [!ai] directive (found via pending_directives) as done. It flips the callout marker at path line line from [!ai] to [!ai-done], so the directive disappears from future pending_directives calls. This tool needs the write scope.

Input:

{
  "path": "Projects/Lettuce.md",
  "line": 42,
  "response": "Done; created Inbox/foo.md and tagged the source.",  // optional
  "fingerprint": "> [!ai] @agent draft the spec"                    // optional
}

Returns: {path, line, response} — the note path, the directive’s line, and the response text spliced in (or null if none).

Errors: directive not found at that line; fingerprint mismatch (line drifted).

Patterns

Self-cleanup on start

Useful for long-lived agents: clear out your stale proposals on each connection. Filter client-side on the fields the list returns.

import datetime
cutoff = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=24)
for p in client.tools.list_my_proposals().proposals:
    if datetime.datetime.fromisoformat(p.timestamp) < cutoff:
        client.tools.withdraw_proposal(id=p.id)

Address-and-acknowledge

for d in client.tools.pending_directives().directives:
    # do the work...
    result = do_the_thing(d)
    client.tools.complete_directive(
        path=d.path,
        line=d.line,
        response=f"Done: {result.summary}",
        fingerprint=d.marker,   # guard against the line drifting
    )

Rotate a proposal when ground truth shifts

for p in client.tools.list_my_proposals().proposals:
    if needs_resubmit(p):
        client.tools.withdraw_proposal(id=p.id)
        # re-submit with fresh context — the same write tool re-queues it
        client.tools.patch_section(path=p.path, ...)

Advisors that pair with proposals

Two read-scoped LLM advisors are the natural source of what to propose. Both are documented in Agent reference/04 Read tools and both require an LLM provider configured (Settings → AI providers, or via env):

Run these, then turn the findings into actual write_note / patch_section / apply_edits calls (which queue as proposals under a propose-only key).