From huntse-agent-skills
Drive a local Anki desktop collection over the AnkiConnect HTTP add-on (port 8765) using a thin Python helper. Add, find, update, tag, move and delete notes and cards; manage decks; check stats. Use when the user asks to work with Anki, flashcards, spaced repetition, decks, notes, or mentions AnkiConnect — anything that needs to read or modify their Anki collection. Requires Anki desktop running with the AnkiConnect add-on (code 2055492159) installed.
How this skill is triggered — by the user, by Claude, or both
Slash command
/huntse-agent-skills:ankiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Drive a local Anki collection from the terminal via the **AnkiConnect** add-on.
Drive a local Anki collection from the terminal via the AnkiConnect add-on.
The helper is a thin generic wrapper — it sends one JSON request to
http://localhost:8765 and prints the result. Claude composes the action and
params; this file documents the common shapes.
2055492159).If Anki is not running, every call fails — check with anki ping first.
The helper lives at ~/.claude/skills/anki/scripts/anki.py after install.
# Sanity check: is AnkiConnect reachable?
anki.py ping
# Find note IDs by query (Anki's standard search syntax)
anki.py find 'tag:M208::A1'
anki.py find 'deck:"My Deck" front:hello'
# Generic invocation: action + JSON params (params optional)
anki.py invoke deckNames
anki.py invoke notesInfo '{"notes":[1700000000000, 1700000000001]}'
# JSON params can also come from stdin
echo '{"query":"tag:M208::*"}' | anki.py invoke findNotes
Output is always JSON on stdout. Errors go to stderr and exit non-zero with the AnkiConnect error string.
All actions use version: 6. Pass params as JSON; the helper wraps the rest.
| Action | Params shape | Returns |
|---|---|---|
version | none | int (API version) |
deckNames | none | list[str] |
modelNames | none | list[str] (note types) |
modelFieldNames | {"modelName":"Basic"} | list[str] |
findNotes | {"query":"tag:foo"} | list[int] (note IDs) |
findCards | {"query":"deck:Default is:due"} | list[int] (card IDs) |
notesInfo | {"notes":[123,456]} | list[NoteInfo] |
cardsInfo | {"cards":[789]} | list[CardInfo] |
getDeckStats | {"decks":["Default"]} | dict keyed by deck ID |
| Action | Params shape |
|---|---|
createDeck | {"deck":"Some::Nested::Deck"} |
addNote | {"note":{"deckName":"X","modelName":"Basic","fields":{"Front":"…","Back":"…"},"tags":["t1","t2"]}} |
canAddNotes | {"notes":[{note}, …]} — duplicate check before adding |
updateNoteFields | {"note":{"id":123,"fields":{"Front":"new"}}} |
addTags | {"notes":[123,456],"tags":"foo bar"} — tags is a space-joined string |
removeTags | {"notes":[123],"tags":"foo"} |
changeDeck | {"cards":[789,790],"deck":"Target Deck"} — uses card IDs, not note IDs |
deleteNotes | {"notes":[123,456]} |
To move notes between decks: first findCards nid:{note_id} (or read
card_ids out of notesInfo), then changeDeck on those card IDs.
createDeck is idempotent — call it before changeDeck if the target deck
might not exist.
Pass these as the query field to findNotes/findCards:
deck:"Some Deck" — quote names containing spacestag:foo — exact tag; tag:foo::* — tag prefix (wildcard)is:due, is:new, is:learn, is:review, is:suspendednid:1700000000000 — note ID; cid:… — card ID"front:exact text" or front:*hello* — field searchOR; group with parensAnki's MathJax wants \( … \) for inline and \[ … \] for display math.
$…$ and $$…$$ will not render. When adding or fixing cards with math,
always use the backslash forms.
addTags and removeTags take tags as a single string with spaces between
tag names — not a JSON array. The note-level tags field on addNote,
however, is a JSON array. Easy to mix up.
addNote raises an AnkiConnect error containing the word "duplicate" if a
card with the same first field already exists in the target deck (Anki's
default duplicate scope is the note type, but it surfaces here per-deck via
AnkiConnect). Either pre-check with canAddNotes or catch the error and skip.
One note can have multiple cards (e.g. forward + reverse). findNotes,
notesInfo, addTags, deleteNotes all operate on notes. findCards,
cardsInfo, changeDeck operate on cards. notesInfo returns each
note's cards field with the card IDs.
notesInfo returns field values with HTML markup intact (br, img, b elements,
etc.). When inspecting content for AI classification, strip tags
first. When writing fields, raw HTML is fine and is how Anki stores
formatting.
Use :: as the separator: M208::E3 Homomorphisms. createDeck will create
all parents on the way down.
notesInfo shape{
"noteId": 1700000000000,
"modelName": "Basic",
"tags": ["tag1", "tag2"],
"fields": {
"Front": {"value": "…", "order": 0},
"Back": {"value": "…", "order": 1}
},
"cards": [1700000000001, 1700000000002]
}
Note the field values are wrapped in {"value": "…"} objects, not raw
strings.
AnkiConnect supports a multi action that runs several actions in one
request — useful for batch updates but easy to misuse. Prefer a loop over
single invoke calls unless you are updating hundreds of notes and latency
matters. Single calls are easier to error-recover from.
collection.anki2 directly while Anki is open — even
read-only, prefer AnkiConnect for consistency with whatever Anki has in
memory. AnkiConnect reads through Anki's own collection object.addNote will reject duplicates and
return an error. Don't swallow the error silently; either skip with a log
line or surface it.$…$ LaTeX — see the gotcha above.npx claudepluginhub huntse/agent-skills --plugin huntse-agent-skillsProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.