SkillAgentSearch skills...

shrike

Manage your Anki collection from the command line or an LLM agent, without opening Anki.

Install / Use

claude mcp add lathrys-at -- npx -y github:lathrys-at/shrike

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

80/100

Supported Platforms

Claude Code
Claude Desktop

Tags

Our assessment of shrike

shrike scores 80/100 on our quality scale, 770th of 960 AI & Machine Learning skills we index.

Its MCP Server is 17 KB long, well organised into 20 sections with 26 code examples: a thorough specification that gives an agent plenty to work with.

It has 3 GitHub stars, so there is little community track record yet; judge it on its content.

Substance
30/30
Structure
20/20
Description
12/15
Adoption
3/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated about 3 months ago, so shrike is actively maintained.
  • Our last check on 2026-09-20 found the source still online.
  • It is released under AGPL-3.0, a copyleft license: you can use it, but modified versions you distribute must carry the same license.
  • Its trust signals score 87/100, with 2 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.

Automated pattern scan on 2026-10-18. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.

shrike compared with similar skills

All 4 of these similar skills score higher than shrike; compare them before choosing.

SkillScoreStarsUpdatedFormat
shrike (this skill)by lathrys-at8033mo agoMCP Server
claude-memby thedotmack100101.5ktodayCLAUDE.md
Agent-Reachby Panniantong10098.9k3d agoCLAUDE.md
Understand-Anythingby Egonex-AI10086.9k6d agoCLAUDE.md
headroomby headroomlabs-ai10075.7ktodayCLAUDE.md

Frequently asked questions

How do I install shrike?
Run claude mcp add lathrys-at -- npx -y github:lathrys-at/shrike. The install tabs above show the steps for each supported agent.
Which AI agents does shrike work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is shrike safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It is AGPL-3.0-licensed and scores 87/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is shrike still maintained?
The repository was last updated about 3 months ago, so shrike is actively maintained.

Shrike

Coverage License: AGPL-3.0 Python: 3.12+

Sometimes you want to work on your Anki collection without opening Anki. That's what Shrike is for. It's a command-line client and an MCP server for your collection, so you can manage cards from a terminal or hand them to an LLM agent.

Shrike works directly on the collection's SQLite database, without using the Anki desktop app or relying on the AnkiConnect bridge. You get:

  • a shrike CLI to browse, create, edit, and delete notes and note types
  • an MCP server exposing the same operations to agents
  • semantic search over your notes, with embeddings computed locally

This README covers running Shrike yourself: install the package, point it at your collection, run the daemon. Desktop, mobile, and web apps built on the same core are planned; docs/distribution.md is the map of where each is headed.

Requirements

  • Python 3.12 or newer
  • An Anki collection (a collection.anki2 file)

Getting started

Install Shrike from PyPI:

pipx install shrike-py   # or: pip install shrike-py

The package is shrike-py; the command it installs is shrike. (It was published as shrike-mcp before; a final shrike-mcp release that depends on shrike-py is published once so an existing pip install shrike-mcp keeps working and pulls the renamed package — but it is frozen, so switch your install to shrike-py.)

Point Shrike at your collection and start the daemon:

shrike server start --collection ~/path/to/collection.anki2

That starts a background daemon with your collection open. The other shrike commands talk to it, so they don't repeat --collection:

shrike collection info
shrike note list --deck Default

And when you're done:

shrike server stop

Semantic search

shrike search finds notes by meaning instead of keywords. To turn it on, declare an embedder in your config file (see Configuration for where the file lives), then start the server as usual. The entry says what kinds of content you want searchable and where the model runs.

Text search with a local model

The simplest setup runs a small ONNX model inside the Shrike process. There is no separate binary to install or keep alive, single-card updates are quick, and a quantized model keeps memory low enough for small machines; this is the setup for a Raspberry Pi. Put a model.onnx and its tokenizer.json in a directory (all-MiniLM-L6-v2 has good small exports, including quantized ones a few times smaller than the default), then:

embedders:
  - modalities: [text]
    runtime: onnx
    model: ~/models/all-MiniLM-L6-v2-onnx

Searching images too

If your cards carry images worth searching by content, use a CLIP export instead: one model that embeds text and images into the same space, so a query like "diagram of the Krebs cycle" can find a card whose answer is a picture, even when the card's text never says so.

embedders:
  - modalities: [text, image]
    runtime: onnx
    model: ~/models/clip-vit-base-patch32

The model directory holds text_model.onnx, vision_model.onnx, tokenizer.json, and preprocessor_config.json; that's the layout of Xenova/clip-vit-base-patch32, and a larger model like jina-clip-v2 searches noticeably better.

A GGUF model through llama-server

If you already use llama.cpp, or the model you want ships as GGUF, declare a remote entry with no endpoint and Shrike runs llama-server for you: spawned at start, stopped with the daemon.

embedders:
  - modalities: [text]
    runtime: remote
    model: ~/models/all-MiniLM-L6-v2-Q4_K_M.gguf
managed:
  llama_server:
    manage: auto
    binary: ~/llama.cpp/build/bin/llama-server   # omit if llama-server is on PATH

Last-token models (Jina v5, Qwen3-Embedding) need pooling: last on the entry; their GGUF metadata doesn't carry it, and without it the vectors come out wrong. BERT-family models like MiniLM and bge need nothing.

A llama-server you already run

If another process owns a llama-server, point Shrike at it instead of spawning a second one. Shrike checks it answers and uses it; it never starts, restarts, or stops it.

embedders:
  - modalities: [text]
    runtime: remote
managed:
  llama_server:
    manage: attach
    port: 8373

A model served somewhere else

Any OpenAI-compatible embeddings endpoint works: a cloud provider, a box on your tailnet. Name the environment variable holding the API key; the key itself never goes in the config file. Keep in mind your note text goes to that endpoint to be embedded, so think before pointing Shrike at a third party.

embedders:
  - modalities: [text]
    runtime: remote
    model: text-embedding-3-small
    endpoint: https://api.openai.com/v1
    api_key_env: OPENAI_API_KEY

Using a GPU

For the in-process entries on an NVIDIA GPU, swap the bundled CPU runtime for the GPU build (pip uninstall onnxruntime, then pip install onnxruntime-gpu; the two can't be installed together) and add providers: [CUDAExecutionProvider] to the entry. On a Mac the plain install already runs on the Apple GPU. Either way, shrike server status shows the provider that actually loaded, so you can confirm the accelerator is in use rather than a quiet fall back to the CPU. For a managed llama-server, set gpu_layers: under managed.llama_server. A floating-point model rather than a small quantized one is what makes a GPU worthwhile, since it can embed cards in larger batches.

Picking a model

Search quality comes from the model, not from where it runs. Text-only models are fully supported everywhere.

| You want | In process (runtime: onnx) | Via llama-server (runtime: remote) | |---|---|---| | Text search | all-MiniLM-L6-v2 ONNX export | all-MiniLM-L6-v2 GGUF | | Text and image search | clip-vit-base-patch32; jina-clip-v2 for better results | not yet; omni models over llama-server are #501 |

One embedder entry at a time for now; running a dedicated text model alongside a CLIP model as separate entries is tracked in #229, and the config error will tell you exactly that if you try.

Reading text inside images (OCR)

OCR support is being reworked. The server no longer bundles Apple's Vision OCR (on-device platform models belong to the mobile apps; the server's replacement is recognition over a configured endpoint, tracked in #502), so --ocr-backend apple currently reports recognition as unavailable rather than scanning your images. Text already recognized by an earlier version stays searchable. When recognition is active, recognized text becomes searchable like field text: exact and typo-tolerant matches work with any backend, and with an embedding backend the text is indexed for semantic search too.

The index

Shrike builds an index of your notes in the background. A large collection takes a little while the first time; search will tell you if it's still indexing. Once it's ready:

shrike search "electron transport chain"
shrike search --similar-to 1700000000123

shrike search also matches your query as exact text and as a near-miss (so protien still finds protein cards); each result shows you which applied. These text matches work even without the embedding service running.

CLI

shrike collection info summarizes the collection: note types, decks, tags, and scheduling stats.

shrike collection info
shrike collection info --types --decks --stats

List and read notes:

shrike note list --deck "Organic Chemistry" --limit 20
shrike note show 1779749914797

Create a note by passing fields with -f:

shrike note create --deck "Japanese::Vocabulary" --type Basic \
  -f Front="読む (よむ)" -f Back="to read"

Cloze notes work the same way; the deletions go in the field:

shrike note create --deck "Systems Design" --type Cloze \
  -f Text="The {{c1::CAP theorem}} says a distributed system can guarantee at most two of {{c2::consistency}}, {{c3::availability}}, and {{c4::partition tolerance}}."

To add notes in bulk, pipe a JSON array to --json-input:

echo '[
  {"deck": "Biochemistry", "note_type": "Basic",
   "fields": {"Front": "What does ATP synthase do?",
              "Back": "Builds ATP from ADP and phosphate, driven by the proton gradient across the inner mitochondrial membrane."},
   "tags": ["metabolism", "mitochondria"]}
]' | shrike note create --json-input

Update fields, edit tags, or delete:

shrike note update 1779749914797 -f Back="to read; to interpret"
shrike note tag 1779749914797 --set verb,jlpt-n5
shrike note delete 1779749914797 --yes

shrike note tag edits a note's tags in one of three modes, and you pick one explicitly:

shrike note tag 1779749914797 --set verb,jlpt-n5         # replace all tags
shrike note tag 1779749914797 --add needs-review         # add, leaving others
shrike note tag 1779749914797 --add jp --remove jp-verb  # add and remove together
shrike note tag 1779749914797 --set ""                   # clear all tags

Fix text across many notes at once with shrike note replace. It needs a scope, previews the changes, and asks before applying:

shrike note replace "teh" "the" --deck "Biology"          # preview, confirm, apply
shrike note replace "colou?r" "color" --regex --tags spelling --dry-run

For tags across the whole collection, shrike collection tag renames:

shrike collection tag rename history::ww2 history::wwii   # rename everywhere it appears
shrike collection tag rename jp japanese --note 1779749914797   # only on these notes

Manage decks with shrike deck:

shrike deck create "Japanese::Vocabulary"      # nested decks use ::
shrike deck rename "Misc::French" "French"      # rename or reparent
shrike deck delete "Old Deck" --yes            # delete (must be empty first)

Anywhere a command takes a deck (including --deck on note commands), you can pass the deck's name, its numeric ID, or #id instead.

Note types have their own commands:

shrike type list
shrike type show Basic
shrike type create --name Vocab --field Word --field Meaning \
  --template 'Card 1:{{Word}}:{{FrontSide}}<hr>{{Meaning}}'

shrike collection media gets images and audio into the collection (reference the stored name from a note field with <img src="..."> or [sound:...]):

shrike collection media store diagram.png                  # upload a local file
shrike collection media store --url https://example.com/cell.png
shrike collection media list '*.png'
shrike collection media fetch diagram.png -o /tmp/out.png  # download it back

Every command takes --json for scriptable output. See the CLI reference for the full list of commands and flags.

Connect an MCP client

Start the server first (see Getting started). Clients connect to the running daemon at http://127.0.0.1:8372/mcp.

Claude Code connects over streamable HTTP directly:

claude mcp add --transport http shrike http://127.0.0.1:8372/mcp

Claude Desktop and claude.ai native URL connectors require OAuth, which Shr

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars3
CategoryAI
Updated2mo ago
Forks3

Languages

Python

Trust signals

87/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

2 low