Skip to content

Agent Integration

sysid edited this page Apr 11, 2026 · 3 revisions

Agent Integration

bkmr's search, storage, and action system works identically for human users and automated agents. The difference is the access pattern: humans use --fzf and browsers; agents use --json, --np, and --stdout.

agent demo

                          bkmr database
                        (SQLite + FTS5 + sqlite-vec)
                               │
              ┌────────────────┼────────────────┐
              ▼                ▼                ▼
         Human Mode       Pipeline Mode     Agent Mode
         ──────────       ─────────────     ──────────
         --fzf            shell scripts     --json --np
         browser open     xargs / awk       --stdout
         clipboard        cron jobs         load-json
         interactive      eval "$()"        hsearch

CLI as API

Every human command has a programmatic equivalent:

Task Human (interactive) Agent (programmatic)
Search bkmr search --fzf bkmr search --json --np
Hybrid search bkmr hsearch "query" bkmr hsearch "query" --json --np
Get content bkmr open <id> bkmr open <id> --stdout
Store memory bkmr add -e (editor opens) bkmr add "content" tags --title "..." -t mem --no-web
View details bkmr show <id> bkmr show <id> --json
Bulk import bkmr import-files ~/docs/ bkmr load-json bookmarks.json
Update fields bkmr edit <id> (editor opens) bkmr update --title "..." --url "..." -d "..." <id>

Programmatic Output Flags

--json

Outputs structured JSON instead of human-formatted text. Available on search, hsearch, and show.

search --json fields:

{
  "id": 42,
  "url": "The memory content or URL",
  "title": "Descriptive title",
  "description": "Optional notes",
  "tags": ["_mem_", "fact", "database"],
  "access_count": 5,
  "created_at": "2026-01-15T10:30:00+00:00",
  "updated_at": "2026-03-20T14:00:00+00:00",
  "accessed_at": "2026-04-05T12:00:00+00:00"
}

hsearch --json fields (includes relevance score, tags as comma-string):

{
  "id": 42,
  "url": "The memory content or URL",
  "title": "Descriptive title",
  "description": "Optional notes",
  "tags": ",_mem_,fact,database,",
  "rrf_score": 0.032
}

Note: hsearch returns tags as a comma-delimited string (,tag1,tag2,), while search returns a JSON array (["tag1", "tag2"]). Parse accordingly.

--np (non-interactive)

Suppresses all interactive prompts. Without it, commands may pause waiting for user input — breaking agent workflows. Always use --np in automated contexts.

--stdout

Outputs the bookmark's rendered content to stdout instead of executing the default action (opening browser, copying to clipboard, etc.). Available on search and open.

# Human: opens URL in browser
bkmr open 42

# Agent: gets the content printed to stdout
bkmr open 42 --stdout

For _mem_ bookmarks, open already prints to stdout by default — but --stdout makes intent explicit and works consistently across all content types.

Agent Memory with _mem_

The _mem_ system tag marks bookmarks as agent memory. When opened, these bookmarks print their content to stdout — no browser, no clipboard, no side effects.

How Memory Bookmarks Work

Field Purpose Example
url The memory content "Prod DB runs PostgreSQL 15 on port 5433"
title Searchable title "Production database connection details"
tags Classification + topics fact,infrastructure,database

System tag _mem_ is added automatically with -t mem. Embeddings are computed from content + title + visible tags, so descriptive titles and tags improve semantic search recall.

Store a Memory

bkmr add "CONTENT" "CLASSIFICATION,TOPIC_TAGS" --title "TITLE" -t mem --no-web

Examples:

# A fact about infrastructure
bkmr add \
  "Production PostgreSQL 15 on db-prod-1.internal:5433. Pool max 50." \
  "fact,infrastructure,database" \
  --title "Production database connection details" \
  -t mem --no-web

# A gotcha that bit you
bkmr add \
  "Tests MUST run with --test-threads=1. SQLite locks cause SQLITE_BUSY errors." \
  "gotcha,testing,sqlite" \
  --title "bkmr tests require single-threaded execution" \
  -t mem --no-web

# A user preference
bkmr add \
  "User prefers pytest over unittest. Always use fixtures." \
  "preference,testing,python" \
  --title "Python testing conventions" \
  -t mem --no-web

Query Memories

Use hsearch (hybrid: FTS + semantic) as the default for natural language queries:

# Hybrid search — best for imprecise queries
bkmr hsearch "database configuration" -t _mem_ --json --np

# Filter to a specific category
bkmr hsearch "deployment steps" -t _mem_ -n procedure --json --np

# Limit results
bkmr hsearch "auth" -t _mem_ --json --np -l 5

Use search (FTS-only) for exact keyword matching:

# Exact phrase
bkmr search '"JWT expiry"' -t _mem_ --json --np

# Boolean: auth but NOT OAuth
bkmr search 'auth NOT oauth' -t _mem_ --json --np

# All gotchas
bkmr search -t _mem_ -n gotcha --json --np

Memory Taxonomy

Use exactly one classification tag per memory:

Tag Use for Content style
fact Infrastructure, config, architecture truths Short declarative statement
procedure How-to sequences, deployment steps Numbered steps or commands
preference User conventions, style decisions "User prefers X over Y because Z"
episode Session summaries, debugging narratives "On DATE, did X because Y, learned Z"
gotcha Non-obvious pitfalls, things that broke "X looks like it works but fails because Y"

Deduplication

Before storing a new memory, check if a similar one exists:

bkmr hsearch "your proposed content keywords" -t _mem_ --json --np -l 3
  • No match → create new memory
  • Outdated matchbkmr edit <id> to update
  • Same content exists → skip
  • Related but adds new infobkmr edit <id> to merge

Session Workflow

Session Start                    During Work                    Session End
─────────────                    ───────────                    ───────────
Query for relevant memories      Check gotchas before           Persist non-trivial
before doing any work            architectural decisions        learnings
                                                                (dedup first!)

bkmr hsearch "<task>"            bkmr hsearch "<topic>"         bkmr hsearch "<learning>"
  -t _mem_ --json --np             -t _mem_ -n gotcha             -t _mem_ --json --np -l 3
  -l 10                            --json --np                  # If no duplicate:
                                                                bkmr add "..." "class,topics"
                                                                  --title "..." -t mem --no-web

What NOT to Store

Anti-pattern Why Do instead
Full file contents Stale immediately, too long Store summary + file path
Git history facts git log is authoritative Store interpretations only
TODO items Ephemeral, belongs in tracker Store the decision behind it
Vague titles like "note" Unsearchable Use specific titles
Anything in CLAUDE.md Already in context Only store what's NOT in docs

Bulk Import

load-json — Structured Bookmark Import

Import a JSON array of fully specified bookmarks:

bkmr load-json bookmarks.json
bkmr load-json bookmarks.json --dry-run  # preview only

Input format (JSON array):

[
  {
    "url": "Production uses Redis 7 for session cache",
    "title": "Redis session cache",
    "description": "",
    "tags": ["_mem_", "fact", "infrastructure", "redis"]
  },
  {
    "url": "https://docs.example.com/api",
    "title": "API Documentation",
    "description": "Internal API reference",
    "tags": ["api", "reference"]
  }
]

Existing bookmarks (matched by URL) are skipped — no update support. Use for migrations, seeding, or agent-generated bulk inserts.

load-json vs import-files

Scenario Command
Agent bulk import / migrations load-json
Import agent memories in bulk load-json (with _mem_ in tags)
Index files with source tracking and smart editing import-files

Integration Patterns

Claude Code / Anthropic Agents

bkmr ships with a ready-made Claude Code skill at skill/bkmr-memory/SKILL.md. Copy it into your .claude/skills/ directory to get a complete memory protocol out of the box — including taxonomy, deduplication, session workflows, and anti-patterns.

The core pattern:

# At session start — recall relevant context
bkmr hsearch "<project> <task>" -t _mem_ --json --np -l 10

# Before decisions — check for gotchas
bkmr hsearch "<topic>" -t _mem_ -n gotcha --json --np

# At session end — persist learnings
bkmr add "what I learned" "classification,topics" --title "title" -t mem --no-web

This pattern works with any agent framework that can execute shell commands and parse JSON.

Shell Script Wrapper

Minimal wrapper for agents that prefer function calls over raw shell:

# Store a memory
bkmr_remember() {
  local content="$1" title="$2" tags="$3"
  bkmr add "$content" "$tags" --title "$title" -t mem --no-web
}

# Query memories (returns JSON)
bkmr_recall() {
  local query="$1" limit="${2:-10}"
  bkmr hsearch "$query" -t _mem_ --json --np -l "$limit"
}

# Get a specific memory's content
bkmr_get() {
  bkmr open "$1" --stdout
}

MCP Server Pattern

bkmr's CLI maps naturally to MCP tool definitions. A minimal MCP server would expose:

MCP Tool bkmr Command
memory_store bkmr add "..." "..." --title "..." -t mem --no-web
memory_search bkmr hsearch "..." -t _mem_ --json --np
memory_get bkmr open <id> --stdout
bookmark_search bkmr search --json --np

Each tool wraps a single bkmr CLI call, parsing JSON output into the MCP response format.

Custom Agents

Any agent that can execute shell commands can use bkmr. The integration requirements are minimal:

  1. Shell exec — ability to run bkmr commands
  2. JSON parsing — parse --json output
  3. No GUI needed--np and --stdout eliminate all interactive prompts

The recommended search command for agents is:

bkmr hsearch "<natural language query>" -t _mem_ --json --np

This combines FTS keyword precision with semantic recall, returns structured JSON, and never prompts for input.

JSON Schema Reference

search --json Output

[
  {
    "id": 42,                                          // integer, unique ID
    "url": "content or URL",                           // string, the bookmark payload
    "title": "Descriptive title",                      // string
    "description": "Optional notes",                   // string
    "tags": ["_mem_", "fact", "database"],             // string array
    "access_count": 5,                                 // integer
    "created_at": "2026-01-15T10:30:00+00:00",        // ISO 8601 datetime or null
    "updated_at": "2026-03-20T14:00:00+00:00",        // ISO 8601 datetime
    "accessed_at": "2026-04-05T12:00:00+00:00"         // ISO 8601 datetime
  }
]

hsearch --json Output

[
  {
    "id": 42,                                          // integer, unique ID
    "url": "content or URL",                           // string
    "title": "Descriptive title",                      // string
    "description": "Optional notes",                   // string
    "tags": ",_mem_,fact,database,",                   // comma-delimited string (NOT array)
    "rrf_score": 0.032                                 // float, higher = more relevant
  }
]

show --json Output

Same schema as search --json (single-element array).

load-json Input Format

[
  {
    "url": "string (required) — content or URL",
    "title": "string (required) — bookmark title",
    "description": "string (optional) — additional context",
    "tags": ["string array (optional) — tag list"]
  }
]

Related Pages

Clone this wiki locally