Update: I will no longer be working on Clanki and RWKV-mini. My Claude Code account randomly got banned and when I requested further investigation, I got this:
I could maaaaaybe work on RWKV, granted it would be very slow and more limited, but there is absolutely no way to maintain an entire Anki fork alone, on my own.
Ngl, I don’t feel great right now.
And I’m not rushing to try Codex or other alternatives because the country where I live is blocked by every LLM provider. For Claude Code I was using a burner phone number + a card with a billing address that has nothing to do with where I live (different country), which is probably why I got banned. Probably. They never specified what exactly I violated.
I’ll keep using my Clanki build, at least until FSRS-7 is integrated into Anki natively. Then I’ll probably switch to official Anki. Maybe someone will look at the history of my Clanki fork (aside from UI, it’s mostly performance optimizations) and use it as a starting point for Anki speedups, but the chances of that are very slim.
EDIT: some of my Clanki speedups are being ported to Anki:
main ← user1823:selection
opened 04:49PM - 04 Oct 26 UTC
Part B1 of https://github.com/Expertium/Clanki/pull/34
## Linked issue (requi… red)
## Summary / motivation (required)
After selecting many cards (e.g. Ctrl+A on ~50k cards) and running a new search, the browser freezes for many seconds.
`DataModel.get_item_rows()` is called from `Table._restore_selection()` to map the saved selection back to row numbers. It tested each table row with `i in items`, where `items` is a list. A list membership test is a linear scan, so the function was O(rows × selected). The work runs on the UI thread, so the whole window locks up.
**Fix**
Build a `set` of the saved items once, then test membership against it:
```python
wanted = set(items)
return [row for row, i in enumerate(self._items) if i in wanted]
```
Set lookups are O(1) on average, so the function is now O(rows + selected).
## Steps to reproduce (required, use N/A if not applicable)
N/A
## How to test (required)
### Checklist (minimum)
- [ ] I ran `./ninja check` or an equivalent relevant check locally.
- [ ] I added or updated tests when the change is non-trivial or behavior changed.
### Details
## Before / after behavior (optional)
No change
## Risk / compatibility / migration (optional)
## UI evidence (required for visual changes; otherwise N/A)
## Scope
- [x] This PR is focused on one change (no unrelated edits).
main ← browser-selection-perf
opened 10:34AM - 06 Oct 26 UTC
## Linked issue
This is a small follow-up to #5755 and #5756.
## Summary
…
I noticed browser selections are still very slow. It turned out QHeaderView was [scanning all row flags on every paint](https://github.com/qt/qtbase/blob/8ba7ea4b77a4b8f1948760221e264917ddc9e1c8/src/corelib/itemmodels/qitemselectionmodel.cpp#L1602). Setting an empty selection model for the header significantly improves performance; the browser can now select 300K rows in a second, while it used to take at least 30 seconds according to my tests.
## How to test
Here's a benchmark test generated by Claude. Save at `qt/tests/browser_selection_bench.py` and run using `out/pyenv/bin/python qt/tests/browser_selection_bench.py --notes 50000`:
[browser_selection_bench.py](https://github.com/user-attachments/files/33101079/browser_selection_bench.py)
Here's a sample run before/after:
```
## Before
created 50000 notes in 2.4s
browser: 50000 rows, 4 columns, Qt platform offscreen
click one row (from all) freeze= 5.2ms busy= 49.0ms done= 634.5ms selected= 1
Ctrl+A freeze= 1167.9ms busy= 1348.8ms done= 1689.9ms selected= 50000
Edit > Select All freeze= 2304.5ms busy= 6193.1ms done= 6244.5ms selected= 50000
Edit > Invert Selection freeze= 4969.9ms busy= 5056.2ms done= 5616.7ms selected= 49999
Shift+click last row freeze= 546.0ms busy= 1095.3ms done= 1530.8ms selected= 50000
Ctrl+click one row (from all) freeze= 1.2ms busy= 5.0ms done= 493.0ms selected= 49999
selected_cards() (all) freeze= 570.4ms busy= 573.5ms done= 597.5ms selected= 50000
selected_notes() (all) freeze= 629.8ms busy= 630.0ms done= 630.1ms selected= 50000
search again (all) freeze= 646.2ms busy= 668.0ms done= 891.1ms selected= 1
toggle cards/notes (all) freeze= 641.5ms busy= 667.7ms done= 1150.9ms selected= 1
toggle red flag (all) freeze= 980.4ms busy= 987.5ms done= 1226.6ms selected= 50000
resize first column (all) freeze= 523.1ms busy= 528.1ms done= 769.8ms selected= 50000
## After
created 50000 notes in 2.4s
browser: 50000 rows, 4 columns, Qt platform offscreen
click one row (from all) freeze= 6.5ms busy= 37.7ms done= 177.2ms selected= 1
Ctrl+A freeze= 11.3ms busy= 21.9ms done= 310.6ms selected= 50000
Edit > Select All freeze= 589.9ms busy= 600.7ms done= 670.7ms selected= 50000
Edit > Invert Selection freeze= 1151.1ms busy= 1163.8ms done= 1221.3ms selected= 49999
Shift+click last row freeze= 6.7ms busy= 30.4ms done= 187.1ms selected= 50000
Ctrl+click one row (from all) freeze= 1.3ms busy= 6.8ms done= 494.6ms selected= 49999
selected_cards() (all) freeze= 618.1ms busy= 618.4ms done= 978.1ms selected= 50000
selected_notes() (all) freeze= 631.7ms busy= 638.3ms done= 983.1ms selected= 50000
search again (all) freeze= 644.9ms busy= 666.3ms done= 983.3ms selected= 1
toggle cards/notes (all) freeze= 680.7ms busy= 720.3ms done= 914.4ms selected= 1
toggle red flag (all) freeze= 1036.1ms busy= 1042.0ms done= 1295.9ms selected= 50000
resize first column (all) freeze= 3.3ms busy= 6.7ms done= 125.9ms selected= 50000
```
I haven’t tried it yet but OpenCode seems to be a popular workaround. Since it’s open source, it can be used from any country, users can use the API of their preferred AI model, and local LLMs can also be used if they have a GPU.