-
Notifications
You must be signed in to change notification settings - Fork 0
storage
This page documents where AI-Hints stores data, what files it creates, and the variables/values it keeps across sessions.
| Location | Contents |
|---|---|
addon/config.json |
Factory default config (tracked in git; the "restore defaults" source). |
Anki profile config (via meta.json / Anki add-on manager) |
Your live configuration, including user data like blacklist state and scan cursors. |
Anki profile ai_hints_bin/pregen_cache.json
|
Pre-generated hint cache (disk-backed; legacy fallback: addon/pregen_cache.json). |
Anki profile ai_hints_bin/ai_hints_batch_state.json
|
Persistent batch queue state (fallback: addon/batch_state.json). |
Anki profile ai_hints_bin/ai_hints.log, .1, .2, .3
|
Rotating log files (current session plus three backups, 5 MB each); resolved via logger._log_path(). |
addon/meta.json.bak, .bak.1, .bak.2
|
Startup copies of the previous addon metadata file, rotated once when an Anki profile opens. |
| In-note hidden JSON block | Per-card generated data (see Data & Storage Format). |
addon/manifest.json, addon/VERSION
|
Package metadata and version string. |
_ai_hints_template.js (media folder) |
Mobile/synced frontend template script. |
addon/config.json is tracked in git and ships with the add-on. It is the source of factory defaults (used by Restore Defaults) and is never modified at runtime.
Every key in this file (with its default value and purpose) is documented in the Configuration Reference (all keys).
Key structure highlights:
{
"ai_provider": "gemini",
"api_keys": { "openai": "", "anthropic": "", "gemini": "", "...": "" },
"models": { "openai": "gpt-4o", "gemini": "gemini-flash-latest", "...": "" },
"model_fallbacks": { "anthropic": ["claude-3-7-sonnet-latest", "..."], "...": [] },
"provider_priority": ["anthropic", "openai", "deepseek", "grok", "gemini", "openrouter", "huggingface", "groq", "sambanova", "nvidia", "mistral", "cerebras"],
"options_count": 4,
"config_version": 3,
"auto_show_hints": true,
"...": ""
}Your actual settings are stored by Anki's add-on manager (persisted to your profile's meta.json). The add-on reads/writes it through mw.addonManager.getConfig() / writeConfig() (via addon/config_io.py).
In addition to the config keys, this live store also holds runtime/user state that is not in the factory defaults:
| Key | Type | Purpose |
|---|---|---|
model_blacklist_data |
object | Persisted blacklist/cooldown state (see below). |
deck_last_scan_nid |
object | Per-deck incremental batch-scan cursors: { "Deck::Sub": <maxNoteId> }. |
last_orphans_check_time |
int | Timestamp cursor for the orphaned-hints scan. |
mobile_setup_completed |
bool | Whether mobile templates were installed. |
last_active_tab |
int | Last selected config tab, restored on reopen. |
supporter_opt_out |
bool | Hide the Support tab auto-open (stored in addon meta). |
local_providers |
object | Legacy local-endpoint provider configs. |
provider_timeouts |
object | Per-provider timeout overrides: { provider: seconds }. |
provider_overrides |
object | Per-provider routing overrides. |
disabled_global_model_priority |
array | Check state for the Advanced Global Fallback dialog. Separate from disabled_fallback_models. |
test_question_front / test_question_back
|
string | The model-testing prompt. |
global_model_priority |
array | The global cross-provider fallback list. |
use_global_model_priority |
bool | Whether the global list is active. |
pre_generate_count |
int | Pre-generation buffer size. |
Persisted by ai_client._save_blacklist() with version 3:
{
"combos_expiries": { "provider|model|key": <unix_expiry_ts> },
"streaks": { "provider|model|key": <failure_streak_count> },
"version": 3
}- Keys use the
provider|model|keycomposite string. -
combos_expiriesholds the timestamp when a failed combo's cooldown ends. -
streaksholds consecutive failure counts (used for blacklisting/sorting).
-
Path:
<profile>/ai_hints_bin/pregen_cache.json(resolved byresolve_data_file(); survives addon updates). -
Class:
PregenCache(aUserDict) inaddon/reviewer_hooks.py. - Purpose: Persist background pre-generated hint data across sessions so pre-generated cards survive restarts and Undo.
- Structure: JSON object mapping card keys to their pre-generated payloads.
- Writes on every set/delete (auto-save).
- Cleared by the 🧹 Clear Pregen Cache maintenance tool.
-
Primary path:
<profile>/ai_hints_bin/ai_hints_batch_state.json(created lazily). -
Fallback path:
addon/batch_state.json(used when no profile is available, e.g. tests). -
Class: written by
batch_manager.py(_state_file_path,load_state,save_state). - Purpose: Persist the batch generation queue so interrupted runs resume after Anki restarts.
Structure (new nested format):
{
"native_jobs": { "<job_id>": { "...": "cloud/native batch job" } },
"local_cache": {
"active": true,
"paused": false,
"last_run_stats": { "...": "..." },
"jobs": [ { "id": "...", "queue": [ ... ] } ]
}
}- Backward-compatible: legacy plain
jobsdicts and oldqueuefields are reconstructed on load. -
Migrated on startup from the old location to the profile folder (see
addon/__init__.py).
| File | Purpose |
|---|---|
<profile>/ai_hints_bin/ai_hints.log |
Current session log — the single canonical location shared by the file handler (rebind_file_logging()), the Logs tab, and Clear Log. |
<profile>/ai_hints_bin/ai_hints.log.1 |
Previous session (rolled at profile open). |
<profile>/ai_hints_bin/ai_hints.log.2 |
Two sessions ago. |
<profile>/ai_hints_bin/ai_hints.log.3 |
Three sessions ago. |
addon/ai_hints.log (legacy) |
Not written anymore. May still exist on disk from older installs; safe to delete. |
addon/ai_hints.log.* (legacy) |
Stale rotated copies from before the profile-scoped migration; safe to delete. |
-
Resolution:
logger._log_path()always resolves to the profile location (<Anki profile>/ai_hints_bin/ai_hints.log). The Logs tab and Clear Log use the same path; there is no separate log stream. -
Handler:
RotatingFileHandler,maxBytes=5*1024*1024,backupCount=3. -
Rotation: 4 files total —
ai_hints.log,.1,.2,.3. A rollover happens when the profile opens so each session starts with a fresh log and three prior sessions are preserved. -
Clear on startup: with
auto_clear_logsenabled (the default) only the currentai_hints.logis deleted on startup; the rotated backups remain available. -
Format:
%(asctime)s - %(levelname)s - %(message)s(e.g.2026-08-28 00:11:24,329 - INFO - AI-Hints usage glm-5.3-flash: prompt_tokens:2334, completion_tokens:1476, total_tokens:3810).
| Level | When | Configured by |
|---|---|---|
DEBUG |
Verbose per-request / per-state traces (request bodies, response bodies, fallback decisions, blacklist/linger events). |
debug_logging in config; Debug logging toggle in the Advanced tab. |
INFO |
Lifecycle events (session start, config save, fetch results, model usage, queue progress). | Always on. |
WARNING |
Recoverable problems (skipped notes, missing optional deps, deprecation). | Always on. |
ERROR |
Failures that affected a generation, fetch, or save. | Always on. |
A line in ai_hints.log is timestamp - LEVEL - message. Useful message prefixes and tokens to grep for:
| Token | Meaning |
|---|---|
New session started. Log cleared. |
Marker emitted at the very start of every Anki session (after rotation/clear). |
meta.json written [addonManager(preserve-merge)] package=ai_hints_dev on_disk_keys=N written_keys=M api_keys=K scan_cursors=C |
One config save — shows on-disk key count, written key count, API-key count, scan-cursor count. The first such line in a session records the on-disk state. |
Configuration saved. |
UI save completed (after the meta.json written line). |
Notification: Fetching models for <provider>... / Notification: Fetching models...
|
Per-provider Fetch Models click. Generic (no provider name) means the provider was unknown to fetch_models and the call returned []. |
Notification: Fetched N models (M new, K missing). |
Fetch success. |
Notification: No models found or endpoint does not support /models. |
fetch_models returned [] with no underlying error — check provider URL/key. |
Notification: Could not fetch models for <provider>. Check connection. |
fetch_models raised and the error was swallowed. |
Notification: Updated fallback priority for <provider> |
Per-provider Fallback dialog save. |
AI-Hints Linger: ... |
A request that timed out was re-dispatched in the background with an extended deadline. Filter on Source → Lingering in the Logs tab to isolate. |
[MODEL_TEST] |
Lines from the per-model Test button / global Test All — request/response payloads, fallback decisions, success/failure, per-model token usage. |
[BLEED] / [BLEED-WRITE]
|
(Debug-only) Card-load source / scope attrs / payload keys / _src presence / target card vs reviewer card match — diagnostic for reports of data bleeding between cards. Gated by debug_logging. |
AI-Hints Custom <provider>/<model> request: / ... FULL REQUEST (system hash <hash>): / ... response: / ... FULL RESPONSE:
|
(Debug-only) Custom (OpenAI-compatible) provider request/response bodies. The system prompt is logged once per system hash. |
AI-Hints usage <model>: prompt_tokens:N, completion_tokens:M, total_tokens:K |
Per-call token usage. Anthropic-style models log input_tokens / output_tokens instead. |
AI-Hints Error (Custom Provider <name>, model <model>): <reason> |
A generation failed — reason is the underlying exception (HTTP 4xx/5xx, timeout, JSON parse, etc.). |
AI-Hints: Trying fallback model for <provider>: <model> |
Fell through to the next enabled model in the per-provider fallback chain. |
AI-Hints: Calling <provider> with model: <model> |
About to make a real chat call. |
AI-Hints: model fetch failed for <provider>: <err> |
fetch_models raised for this provider; the loop continues to the next. |
AI-Hints: Failed to fetch models for <provider>: <err> |
Final fetch_models error after all retries. |
Blacklisted combo (<provider>, <model>, <key-prefix>) |
A (provider, model, api_key) triple was added to the cooldown/blacklist sidecar. |
Failed to bind log file handler |
Logger could not attach the rotating file handler at profile open — log is buffered in memory only until the next session. |
Batch job completed / AI-Hints: Batch job completed
|
End of a batch run. |
Counting skipped cards x/y |
Progress during a deck unskip scan. |
The in-addon Logs tab reads the same ai_hints.log file (streamed in a background thread, capped at the newest 4,000 matching lines). It offers:
-
Level dropdown —
DEBUG/INFO/WARNING/ERROR/ALL. -
Source filter —
All,Standard Addon,Batch Processing,Pre-generation,Model Testing,Lingering(theAI-Hints Linger: ...lines). - Free-text search.
-
Clear Log — empties the current
ai_hints.log(rotated backups are not affected). The header showsmatched / total linesplus truncation info. -
Auto-clear on startup —
auto_clear_logsconfig key (defaulttrue).
-
Desktop: the
Anki2/<profile name>/directory under your Anki data folder (e.g.~/Library/Application Support/Anki2/User 1/,%APPDATA%\Anki2\User 1\, or~/.local/share/Anki2/User 1/). - AnkiWeb / AnkiDroid / AnkiMobile: logs are not written locally; the on-device install does not have a file log.
- The on-screen Open Log Folder shortcut (when present) opens the resolved
ai_hints_bindirectory.
Generated hints/options are stored in a hidden <div class="ai-hints-json"> block inside each note. This is the core per-card data. See Data & Storage Format for the full payload fields (hints, options, correct_answer, _src, _provider, _model, _generated_at, _generation_type).
| File | Contents |
|---|---|
addon/manifest.json |
name, package, version, human_version. |
addon/VERSION |
Plain version string (e.g. 6.1.0), read at import for auto-regeneration version checks. |
-
File:
_ai_hints_template.jsin your Anki media folder. -
Source:
addon/web/template.js. - Purpose: The lightweight JavaScript renderer used by AnkiDroid, AnkiMobile, and AnkiWeb (Zero-Addon architecture).
- Installed/removed by the Mobile Support tab and synced to AnkiWeb.