Skip to main content
Glama
Anki Card Manager (acm)

Anki Card Manager (acm)

by Eduvent

Anki Card Manager (acm)

Capa local entre Claude y Anki. Vos creás tarjetas conversando con Claude; acm las deduplica (entre todos los mazos, por similitud semántica), clasifica, rutea y sube a Anki — sin copiar/pegar ni organizar a mano.

Es un connector MCP (lo usa Claude como herramienta) y también un CLI. Todo corre local: embeddings, dedup y clasificación con Ollama; tu material no sale de tu máquina.


Qué hace

El flujo que automatiza es crear → revisar → subir:

  1. Claude propone tarjetas y llama a acm_annotate. Cada tarjeta vuelve anotada (sin subir nada): ¿es duplicada y de cuál?, mazo sugerido, tags, confianza, flags de calidad. Mostrás una lista ya deduplicada y clasificada.

  2. Aprobás las que van → se persisten en una cola con estado.

  3. acm_sync las inserta en Anki vía AnkiConnect, ruteadas y taggeadas. Se elimina el copy-paste.

Principios: no destructivo (nunca borra/fusiona sin tu OK), economía de tokens (resuelve local y solo escala a Claude el caso difícil), cualquier materia (cero lógica de dominio en el código; la taxonomía vive en config).

El motor de deduplicación

Usa embeddings como recuperador kNN (coseno) sobre toda la colección, con atajo exacto por huella. Captura paráfrasis sin solape de palabras —incluso cross-lingual ES↔EN— que un motor léxico se perdería. Si Ollama no está disponible, degrada con gracia a una capa léxica y lo reporta (embeddings_used: false). Ver SPIKE_EMBEDDINGS.md para la elección de modelo y la calibración.

La escalera de clasificación (barata → cara)

determinista (taxonomía/keywords en config) → propagación por kNN (vecinos ya etiquetados) → LLM local (Ollama, opcional) → Claude (solo el residuo). Solo se auto-aplican tags con alta confianza; lo ambiguo se marca para vos.


Related MCP server: MCP-AnkiConnect

Requisitos

  • Python ≥ 3.11

  • Ollama con el modelo de embeddings:

    ollama pull qwen3-embedding:0.6b
    # opcional, para el fallback de clasificación con LLM local:
    ollama pull qwen2.5:0.5b-instruct   # o uno más capaz, p.ej. qwen2.5:7b-instruct
  • Anki con el addon AnkiConnect (solo para subir/auditar; el resto funciona offline).

Instalación

# con uv (recomendado)
uv venv && uv pip install -e .

# o con pip
python -m venv .venv && .venv/bin/pip install -e .

Esto instala los comandos acm (CLI) y acm-mcp (servidor MCP).

Datos y configuración (ACM_HOME)

El registro, índices, colas y backups viven en ACM_HOME (env var, default ~/.acm). Es una ruta absoluta independiente del cwd, así Claude puede lanzar el MCP desde cualquier directorio sin partir el registro.

La config está en config/settings.yaml (modelo de embeddings, umbrales, perfiles, reglas de dominio data-driven) y la taxonomía en config/taxonomy.yaml.


Uso

Como connector MCP en Claude

Agregá el servidor a tu configuración de Claude (Desktop/Code), por ejemplo:

{
  "mcpServers": {
    "anki-card-manager": { "command": "acm-mcp" }
  }
}

Tools expuestas (13):

Tool

Qué hace

acm_annotate

Anota candidatas (dup/mazo/tags/calidad) sin subir. El punto de entrada.

acm_ingest

Persiste un lote (clasifica + dedup + encola).

acm_resolve

Resuelve la cola con una acción: approve / reject / correct.

acm_review

Lista la cola de revisión (dups + ambiguas) con su estado.

acm_sync

Sube las aprobadas a Anki (idempotente; dry_run, fallback TSV).

acm_undo

Deshace un lote de sync (borra esas notas + revierte estado).

acm_audit

Audita un mazo: mode=duplicates|recent|untagged|suggest_taxonomy|maintenance.

acm_reorganize

Reorganización masiva one-shot (dry-run + backup previo).

acm_find_similar_card

Busca similares a un front/back dado.

acm_apply_tags

Aplica tags a notas nuevas o existentes (por note_id).

acm_auto_classify

Clasificación determinista token-eficiente (sin LLM).

acm_taxonomy

Consulta/edita la taxonomía: action=show|add.

acm_stats

Estadísticas + métricas de observabilidad + lotes deshacibles.

Como CLI

acm ingest cards.json            # procesa un archivo de tarjetas
acm review                       # ve la cola de revisión
acm approve <id>  /  acm reject <id>
acm sync                         # sube las aprobadas (--export-tsv como fallback)
acm audit-duplicates --deck "Cloud Certs"
acm similar --front "¿Qué es un CDN?"
acm taxonomy show

Estados de una tarjeta

propuesta (anotada, sin persistir) → en-revisión (duplicado posible o tags ambiguos) → aprobada (lista para subir) → subida (en Anki) · descartada.

Las aprobadas son la cola offline: si Anki está cerrado, esperan y suben al reconectar (o se exportan a TSV).


Desarrollo

# tests (corren sin Ollama: degradan a léxico)
.venv/bin/python -m pytest -q

# validación del motor de embeddings (elección de modelo + calibración)
PYTHONPATH=. .venv/bin/python scripts/spike_knn.py

# validación end-to-end sobre tu colección real
PYTHONPATH=. .venv/bin/python scripts/validate_real.py

Arquitectura: la lógica de negocio vive en acm/pipeline/ (motor de similitud, clasificación, calidad, propagación, LLM) y acm/service.py (sync, cola, undo, backup). acm/mcp_server.py y acm/cli.py son adaptadores finos. acm/store/registry.py es el SQLite (registro + índice + cache de embeddings).

Available Tools

13 tools
acm_annotateA

Anota tarjetas candidatas SIN subir ni persistir nada (E3-1 / RF-A2).

Es el corazón del flujo "crear → revisar → subir": Claude propone cards y llama a esto; cada card vuelve anotada para que muestres al usuario una lista YA deduplicada y clasificada. No escribe en el registro ni en Anki.

Por cada card devuelve:

  • es_duplicado (bool) + matches (id, deck, score, razón) cross-deck

  • mazo_sugerido, tags_sugeridos (alta confianza), tags_ambiguos

  • confianza (high/medium/low), flags_calidad, material_origen

Args: cards_json: JSON array. Cada card: front, back, source, y opcionales suggested_tags ("category::value"), note_type, profile, deck, material_origen (PDF/sección de origen). verbose: False (default) → matches compactos (top-2) para economía de tokens (§9); True → detalle completo de cada match.

Inputs: cards_json (required), verbose. Returns: result

acm_apply_tagsA

Aplica tags decididos por el agente o humano a tarjetas.

Úsalo después de acm_auto_classify para las tarjetas en needs_review. Puede aplicar tags tanto a tarjetas nuevas (por índice del batch) como a notas existentes en Anki (por note_id).

Args: assignments_json: JSON array de asignaciones. Cada una tiene: - tags (list[str]): Tags en formato "category::value" Y uno de: - note_id (int): Para notas ya existentes en Anki - card (dict): Para tarjetas nuevas, con front/back/source file: Ruta opcional a un archivo JSON/YAML con las asignaciones.

Returns: JSON con resultados: tags aplicados, errores de validación, tarjetas procesadas vía el pipeline normal de ingest.

Inputs: file, assignments_json. Returns: result

acm_auditA

Audita un deck de Anki — una sola tool para tres modos (E6-2).

Modos:

  • "duplicates": clusters de tarjetas repetidas (dedup local kNN cross-deck).

  • "recent": audita lo creado en Anki en los últimos days días (dups + tags faltantes). Para la pasada de "lo que hiciste a mano" (RF-F1).

  • "untagged": notas sin tags de taxonomía completos; auto-taggea las de alta confianza y devuelve solo las ambiguas, paginadas.

Args: deck: deck raíz a auditar. mode: "duplicates" | "recent" | "untagged". profile: perfil de taxonomía (default: el de settings). include_subdecks: incluir subdecks (default True). days: ventana temporal para mode="recent". include_registry: incluir el registro local en mode="duplicates". limit, offset: paginación para mode="untagged".

Inputs: deck (required), days, mode, limit, +4 more. Returns: result

acm_auto_classifyA

Clasifica tarjetas determinísticamente sin usar LLM. Retorna las que se pudieron resolver y las ambiguas que necesitan intervención del agente.

Flujo token-eficiente: llama esto primero. Solo las cards en "needs_review" requieren que el agente las analice y llame acm_apply_tags.

Args: cards_json: JSON array de tarjetas. Cada tarjeta tiene: - front (str): Pregunta - back (str): Respuesta - source (str, opcional): Origen (default "manual") - suggested_tags (list[str], opcional): Tags existentes "category::value" - note_type (str, opcional): Tipo de nota Anki (default "Basic")

Returns: JSON con: - classified: tarjetas resueltas con alta confianza (no requieren tokens) - needs_review: tarjetas ambiguas con contexto para que el agente decida - taxonomy: categorías válidas (solo si hay items en needs_review) - summary: conteos

Inputs: cards_json (required). Returns: result

acm_find_similar_cardC

Busca tarjetas similares a un query usando el motor local de duplicados.

Inputs: front (required), back, deck, profile. Returns: result

acm_ingestB

Procesa tarjetas candidatas: normaliza, clasifica, deduplica, decide y persiste.

Args: cards_json: JSON array de tarjetas. Cada tarjeta tiene: - front (str, requerido): Pregunta de la tarjeta - back (str, requerido): Respuesta de la tarjeta - source (str, requerido): Origen ("claude", "chatgpt", "manual") - suggested_tags (list[str], opcional): Tags en formato "category::value" - note_type (str, opcional): Tipo de nota Anki (default "Basic") on_exact_match: qué hacer si el contenido ya existe (mismo fingerprint): "update" (default, actualiza el registro existente — idempotente), "skip" (no toca el existente) o "new" (crea uno nuevo). Evita duplicar el registro al re-ingerir (reporte §7).

Returns: JSON con la decisión/persistencia por tarjeta (insert/possible_duplicate/ reject/updated/skipped).

Inputs: cards_json (required), verbose, on_exact_match. Returns: result

acm_reorganizeA

E7-3: reorganización masiva (one-shot) de un mazo — re-taggea y reporta dups.

dry_run=True (default) previsualiza SIN tocar nada (E9-1). Al aplicar, hace backup del registro (E9-3), auto-taggea en Anki las notas de alta confianza y reporta los duplicados para revisión (NUNCA fusiona; decisión #2).

Args: deck: deck raíz a reorganizar. profile, include_subdecks: comunes. dry_run: True previsualiza; False aplica (con backup previo).

Inputs: deck (required), dry_run, profile, include_subdecks. Returns: result

acm_resolveA

Resuelve un item de la cola de revisión con UNA sola acción (E5-1 / E5-3).

Funciona en CUALQUIER estado (id completo o prefijo), no solo en la cola activa (§6). La cola incluye duplicados posibles y clasificación ambigua.

Args: record_id: ID completo o prefijo del registro. action: "approve" (→ aprobada), "reject" (→ descartada), "purge" (borrado físico del registro) o "correct". front, back: contenido corregido (requeridos para action="correct"). tags: tags sugeridos para la corrección (opcional, "category::value"). note_type, deck: corrección opcional de modelo/mazo (§5).

Para "correct", la card corregida REINGRESA al pipeline: se re-deduplica y re-clasifica automáticamente (E5-3).

Inputs: action (required), record_id (required), back, deck, +3 more. Returns: result

acm_reviewA

Lista tarjetas marcadas como possible_duplicate pendientes de revisión.

Returns: JSON con la lista de tarjetas pendientes, cada una con id, front, vendor, topic y fecha.

Inputs: no named parameters. Returns: result

acm_statsA

Muestra estadísticas del registro de tarjetas procesadas.

Returns: JSON con conteo por acción (insert, possible_duplicate, reject) y total.

Inputs: no named parameters. Returns: result

acm_syncA

Empuja las tarjetas aprobadas pendientes a Anki, ruteadas e idempotente.

Re-correr no recrea: las subidas pasan a estado 'subida' y se saltan (E4-3). Anki cerrado → las aprobadas quedan encoladas y suben al reconectar; con export_tsv (ruta) además se exportan a TSV (E4-5). dry_run=True muestra el plan sin tocar Anki (E9-1). Antes de subir hace backup del registro (E9-3) y devuelve un batch_id deshacible con acm_undo (E9-2).

Returns: JSON con synced (id/deck/note_id), errores, batch_id y backup.

Inputs: dry_run, export_tsv. Returns: result

acm_taxonomyA

Consulta o edita la taxonomía de tags (E6-2: show + add en una tool).

Args: action: "show" (default, lista categorías y valores) o "add". category: categoría del tag (requerido para action="add"). value: valor a agregar (requerido para action="add"); crea category::value. profile: perfil cuya taxonomía consultar/editar.

Returns: JSON con la taxonomía (show) o el resultado de la operación (add).

Inputs: value, action, profile, category. Returns: result

acm_undoA

Deshace un lote por id (E9-2 / §5). Detecta el tipo automáticamente:

  • lote de SYNC (de acm_sync): borra esas notas de Anki y revierte las tarjetas a 'aprobada'.

  • lote de INGEST (de acm_ingest): borra del registro las tarjetas creadas en esa ingesta (no toca las ya subidas a Anki).

Mirá los lotes disponibles (sync_batches / ingest_batches) con acm_stats.

Args: batch_id: id del lote (lo devuelven acm_sync / acm_ingest y los lista acm_stats).

Inputs: batch_id (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 13 tools

    Disambiguation4/5

    Most tools have distinct purposes, but there is minor overlap between acm_annotate, acm_auto_classify, and acm_ingest regarding classification. Also, acm_audit and acm_reorganize both involve duplicate detection. Overall, an agent can generally distinguish them.

    Naming Consistency4/5

    All tools share the 'acm_' prefix and most use verb-based names (e.g., acm_annotate, acm_ingest). However, a few are nouns (acm_stats, acm_taxonomy), breaking the verb_noun pattern. Still, naming is largely predictable.

    Tool Count5/5

    13 tools is well-suited for an Anki card manager. Each tool addresses a specific stage in the workflow (annotate, classify, ingest, review, sync, etc.) without being excessive or insufficient.

    Completeness4/5

    The tool set covers the core lifecycle: candidate annotation, classification, ingestion, review, sync, and audit. Minor gaps exist, such as lacking a direct card edit tool (though acm_resolve provides correction). Overall, the surface is comprehensive for the domain.

    Related MCP Connectors

    Related MCP Servers