loopky
/loopky
Tworzy talie fiszek Loopky w stylu Anki z tematu, pliku TSV lub .apkg, z powtórkami w odstępach i nauką języków.
- Autor
- jvsena42 ↗
- Repozytorium
- loopky ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 25.10.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 8
Brak sygnałów. Repozytorium zmienione 25.10.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Tworzy talie fiszek Loopky w stylu Anki z tematu, pliku TSV lub .apkg, z powtórkami w odstępach i nauką języków.
Oryginalny opis (EN)
Build and manage Loopky flashcard decks with the `loopky` CLI or the Loopky connector - make Anki-style spaced-repetition cards from any topic, import a TSV or (with the CLI) an Anki .apkg, add, edit or illustrate cards, publish a language deck with Listen/Speak, or learn a language from a TV series' episodes. Use whenever the user asks for flashcards, Anki cards, a study, vocabulary or exam deck, spaced repetition, or mentions Loopky, even if they do not name the CLI. Also use when a `loopky` command or a Loopky tool returned an error or an exit code.
Jak działa
- CLI or connector
- Workflow
- Exit codes
- Writing good cards
- Where to find pictures
- General language decks
- Decks from a TV series
- Limits worth knowing
- Reporting friction to Loopky
Podgląd SKILL.md
---
name: loopky
description: Build and manage Loopky flashcard decks with the `loopky` CLI or the Loopky connector - make Anki-style spaced-repetition cards from any topic, import a TSV or (with the CLI) an Anki .apkg, add, edit or illustrate cards, publish a language deck with Listen/Speak, or learn a language from a TV series' episodes. Use whenever the user asks for flashcards, Anki cards, a study, vocabulary or exam deck, spaced repetition, or mentions Loopky, even if they do not name the CLI. Also use when a `loopky` command or a Loopky tool returned an error or an exit code.
---
# Loopky flashcards through the `loopky` CLI
Loopky is a free spaced-repetition flashcards app (Android, iOS). `loopky` is its headless client:
it writes decks to the user's own account, and they study them on their phone. It manages decks and
cards; it does not study.
**If the user needs a file for Anki itself** (an `.apkg` to open in Anki), Loopky is not that:
say so, and offer Loopky as the option rather than substituting it. Loopky *imports* Anki decks;
it does not export them.
**The binary is the reference, this file is the workflow.** Flags, operands, result shapes and exit
codes come from `loopky commands --json` and `loopky <command> --help`. Read them rather than
guessing, and trust them over anything here.
## CLI or connector
Loopky has two doors onto the same account: the `loopky` CLI, and a hosted connector
(`https://mcp.loopky.app/mcp`) whose tools — `deck_list`, `deck_create`, `card_add`, `import` and
the rest — take the CLI's options as inputs (`--front-lang` is `front_lang`). In Claude Code a
connector's tools show up as `mcp__claude_ai_Loopky__deck_create` and similar. Pick by where you
are running:
- **No shell at all** (a chat app): the connector is the only door. If its tools are not there,
tell the user to add it from Claude's connector directory — Settings → Connectors → Browse
connectors, search for Loopky, or open https://claude.ai/directory/loopky — then sign in with
Pubky Ring when it asks.
- **A shell on the user's own machine** (a local terminal): **use the CLI**, with the workflow
below. It is the complete client: `.apkg` imports, card files on disk, `--check-images`,
`batch` and `card reorder` exist only there. If `loopky` is missing, offer the install; mention
the connector only if they would rather not install anything.
- **A cloud or sandbox session** (Claude Code on the web, Codex cloud, a container — `/.dockerenv`
or `/run/.containerenv` exists, or the environment is recreated per task; a proxy in
`HTTPS_PROXY` counts only beside one of these, since a laptop behind a company proxy is still
the user's own machine): **recommend the connector.** The CLI there has to be installed every session,
needs several hosts on the sandbox's allowlist, and needs the user at their phone for a new
sign-in about every hour. If the connector's tools are attached, use them. If they are not,
your answer still starts with adding it — Loopky in the connector directory, one Ring sign-in —
rather than with installing the CLI; use the CLI only if the user prefers it or needs what only
the CLI has.
Through the connector:
- **Skip the CLI's steps**: no `--version`, `doctor` or `login`. The user signed in when they added
the connector. A result carrying `error.reconnect: true` means they have to reconnect it, and
nothing else helps.
- **The workflow is otherwise the same**: show the cards, `dry_run: true` first and fix its
advice, publish, then verify with `deck_show` and `card_list`.
- **Cards go inline**, as `cards` (objects) or `text` (TSV or JSONL), at most 2,000 cards and
1 MiB a call. A bigger deck is a `deck_create` and then `card_add` calls, which append.
- **It refuses what would make the server touch something of its own**: file paths (it cannot see
the user's disk), an Anki `.apkg` (point them at the CLI for that), and `check_images` (the
server never fetches a caller's URL; the phone fetches pictures).
- **No `batch`, `card reorder` or deck delete.** One write at a time per account: wait for a call
to return before the next.
- Results are the CLI's `--json` envelope, so the exit-code names below are the `error.code`
values the tools return.
## Workflow
1. **In a cloud or sandbox session, or with no shell, read "CLI or connector" above first**: there
the connector comes before any install. Otherwise, **check the CLI is there:**
`loopky --version`. If it fails, **stop** and ask the user to
install `loopky`, pointing them at <https://github.com/jvsena42/loopky/tree/main/cli#install>
(Homebrew, a `.deb`, or the release installer for Linux, macOS and Windows). Do not download or
install it yourself — this plugin runs only code that was reviewed with it. If a cloud session's
user chose the CLI over the connector, suggest installing it in the environment's setup script
so the next session has it. Once they
have, run `loopky --version` again; if the shell cannot find it, it is usually in
`~/.local/bin` (Windows: `%LOCALAPPDATA%\Programs\loopky`), which has to be on `PATH`.
2. **Read the surface:** `loopky commands --json`. No session, no network.
3. **Check the network:** `loopky doctor --json`. On exit 14 or 15, **stop**: the sandbox's
allowlist blocks hosts Loopky needs, and only the user can change it. Show them `data.next_step`
and `data.allowlist` verbatim — the hosts, and where their product keeps that setting. No
package, script or retry can add a host for them.
4. **Sign in:** `loopky login --json --timeout 300`. The user approves with Pubky Ring on their
phone. Show them the QR code **and** the `auth_url` from the output in a code block — on the
device they chat from, they may open the link instead of scanning. The link is a login secret
until approved: show it only to them, nowhere else. Exit 13 means nobody approved in time; run
`login` again for a fresh code. A session lasts about an hour.
5. **Write the cards to a file** (TSV: `front<TAB>back`, optionally two more columns of `https`
image URLs, one per side; JSONL when a side holds a tab or a newline). Show the user the list
before publishing anything; for a deck too long to read, show what "A deck too long to show"
below lists instead. Keep working files (card files, downloaded sources, your scripts)
in the user's working directory or one they name, not the system's temporary directory, which
a long session can lose with everything in it.
6. **Dry-run every write first:**
```shell
loopky deck create --title "<Title>" --from-file cards.tsv --dry-run --json
```
`--dry-run` exists on `deck create`, `card add` and `import`, and runs that command's own
parser. Read `image_advice`, `card_advice` and `language_advice` in the result and fix what
they name: they are advice, so the command still exits 0 with them in it.
7. **Publish:**
```shell
loopky deck create --title "<Title>" --tag <topic> --from-file cards.tsv --json
```
Add `--id <word> --if-not-exists` when a retry must not publish a second deck. A tag is stored
lowercase, without accents and with `-` between words (`Bioquímica Básica` becomes
`bioquimica-basica`); `tags_normalized` in the result lists each one that changed, and that is
not an error.
8. **Verify from what was stored, not what was sent:** `loopky deck show <deckId> --json` and
`loopky card list <deckId> --json`. Results sit under `data`; a card's `front` is an object with
`.text` and `.image`, not a string. Tell the user the deck is on their phone under the title.
9. **If the CLI or this skill got in the way, ask whether to report it**, once, at the end, as
the last section describes. Nothing is gathered before a yes, and nothing is sent until the
user approves the exact text.
**Several commands in a row belong in `loopky batch`.** Each invocation pays ~2s of start-up and a
session round trip; a batch pays once. One JSON line per operation:
`{"argv": ["card", "add", "<deckId>", "--front", "…", "--back", "…"]}`, run with
`loopky batch ops.ndjson --json`. Its output is one JSON line per operation, as each one runs,
then a summary line last: read it line by line, since parsing it as one document fails. It is
not transactional: on failure, fix the cause and re-run the same file — `card add`,
`card edit --from-file` and `deck create --id --if-not-exists` skip what already landed.
**One write at a time per deck.** Each write replaces the deck's whole record of where its cards
are, so two at once can drop one's cards with both reporting success. On one machine `loopky` makes
the second command wait and says so on stderr; nothing can make it wait for a command on another
machine or in another sandbox. So agents working in parallel write card files, and one process
publishes them, one command after another or as one `loopky batch`.
**Slow is not stuck.** `card edit --from-file` costs about a second a row and a whole-deck
`card reorder` minutes on a deck of thousands. Under `--json` a long write prints
`loopky: still working - <done>/<total>` on stderr as its writes complete, at most every 15
seconds. Each line means progress, so wait while they arrive. A gap is not proof of a hang: one
request may be slow, or the command may be reading the deck, which reports nothing. Give it a few
minutes before treating it as stuck. A session lasts about an hour, so split an edit of thousands
of rows across files.
**A card in the wrong place moves with `loopky card mv <deckId> <cardId> --after <cardId>`**, or
`--to <position>`, counting from 1 as `card list` prints them. Never delete and re-add a card to
move it: the new card has a new id, and everyone studying the deck loses their progress on it. A
move keeps it. Put several moves in one `loopky batch`: each `card mv` reads the whole deck before
its one write, and only a batch pays for that read once. A card already in place writes nothing,
so the file can be re-run. Keep `card mv` to a few cards.
**Many cards out of place, reorder the whole deck from a file.** `loopky card list <deckId>`
prints one card a line with its id first; put those lines in the order wanted and run
`loopky card reorder <deckId> --from-file order.txt --dry-run`, then without `--dry-run`. Only the
first column is read, and the file has to name every card exactly once, or nothing is written.
Every card keeps its id, so nobody studying the deck loses progress. If it fails partway (exit 4,
5 or 12), run the same command again with the same file: that finishes it, and until then the
deck still has every card but refuses card writes with exit 9. If the file is lost, the output of
`card list` works as the file. `card add` only appends, so cards that belong in the middle of a
deck are added first and placed with one reorder afterwards: build the whole order once, since
every reorder rewrites the deck.
**Already have an Anki deck?** `loopky import deck.apkg --dry-run --json` first — check which
fields became front and back (`--front-field`/`--back-field` override it) and `images.bytes`, since
an `.apkg` is the one import that uploads pictures against a 1 GB quota. Then
`loopky import deck.apkg --title "<Title>"`.
## Exit codes
Branch on the exit code (or `error.code` in the JSON) before reading the message.
| Exit | Name | What to do |
| --- | --- | --- |
| 0 | ok | Carry on. |
| 1 | internal | Report it as a bug; do not loop on it. |
| 2 | usage | Fix the command line with `loopky <command> --help`. Never retry unchanged. |
| 3 | not_signed_in | Run `loopky login` with the user. |
| 4 | session_expired | Stop and ask the user to approve a new `loopky login`, then re-run what failed. Writes die after about an hour while reads still work. |
| 5 | network | Retry as-is, a few times with a pause. |
| 6 | not_found | Check the id with `loopky deck list --json`. |
| 7 | storage_full | Terminal: the account is out of quota. Never retry; tell the user. |
| 8 | environment_mismatch | The session belongs to the other network; run the next command with the `--env` the message names. From `login` the session is already stored: do not log in again. |
| 9 | bad_input | Fix the file or operand the message names. Never retry unchanged. |
| 10 | unsupported_host | No build for this OS/architecture. Nothing to retry. |
| 11 | update_unsupported | `loopky update` refused and **nothing was updated**; run the command its message names (brew, dpkg…). |
| 12 | server_error | Homeserver 5xx; the write may have landed. Retry — the idempotent commands skip what did. |
| 13 | timeout | Nobody approved the login in time; run `loopky login` again. |
| 14 | proxy_refused | Allowlist problem. Back to `loopky doctor` and hand the user its host list. Retrying will not help. |
| 15 | tls_untrusted | A proxy is re-signing TLS. Back to `loopky doctor`; the user must exempt the hosts or name the CA with `SSL_CERT_FILE`. |
| 16 | homeserver_unresolved | Transient name lookup failure; retry. Not an allowlist problem. |
| 17 | request_refused | The indexer refused the request this binary built (a version mismatch). Do not retry; run `loopky update`, and report it if the latest release still fails. |
## Writing good cards
- **One fact per card.** A back that needs "and" is two cards, and so is one with alternatives
(`vegetariano / vegetariana`): split it, or keep one form. Short fronts, short backs.
- **Fix a card before showing the list, never annotate it.** If you notice a card breaks a rule
here, rewrite it; the user reviews cards, not caveats about them.
- **Parenthesized asides are notes, not answers.** `hola (informal)`, `猫(ねこ)`: the card shows
the note, but typing and Speak grade only `hola`/`猫`. Unbracketed, the note becomes part of the
expected answer.
- **Language decks declare their pair.** `--front-lang en-US --back-lang es-ES` (BCP-47) is what
makes `--listen` and `--speak` work, and it also tags the deck `language` and `spanish` so learners
find it. Without the pair the phone would read Spanish in an English voice, so `loopky` refuses
either switch until both languages are given (exit 2).
`--type` (typed answers) and `--reverse` (ask both directions) need no pair.
- **Pictures are `https` URLs, never uploads.** SVG, TIFF, WebM and STL do not render on either
phone, whatever the host: use a JPEG, PNG or WebP. Add `--check-images` to the dry-run when the
URLs came from anywhere you have not fetched. Which source to take them from is the next section.
- **Tags are public** and indexed network-wide. Use a few honest topic words, each at most 20
characters; never copy an Anki deck's tags or description without reading them.
- **Every front leads to one answer, and with `--reverse` every back does too.** Two cards with the
same front cannot both be answered, and typing and Speak grade the other one's answer wrong. Give
the rarer synonym a short aside in the learner's language (`começar → start`,
`começar (formal) → commence`); give two senses
of one word an aside on the back (`bank (money)`, `bank (river)`), or keep the commoner sense.
- **An aside never holds the answer or part of it**, in either language: a note that names the
target word turns the card into reading practice.
- **Do not pad.** Make the cards the user asked for, at the count they asked for.
## Where to find pictures
A picture is a prompt, so it goes on the side that asks: the thing on the front, its name on the
back. Every deck is public and a card has no room for a credit line, so the licence decides the
source as much as the topic does.
**Try the sources in this order, and move to the next when one has no picture that shows exactly
the card's fact, its host is blocked (`loopky doctor` lists them under `recommended`), or the
picture's licence is not one of those below.** When none has one, leave the card without a
picture: a near miss teaches the wrong thing.
1. **A source made for the topic**, when there is one. All public domain, nothing to credit.
| Topic | Find it | The URL that goes on the card |
| --- | --- | --- |
| Country flags | the ISO 3166 code, no lookup | `https://flagcdn.com/w640/<code>.png`. Widths double from `w20` to `w2560`; anything else 404s. |
| Space, astronomy, NASA missions | `images-api.nasa.gov/search?q=…&media_type=image` | `https://images-assets.nasa.gov/image/<nasa_id>/<nasa_id>~medium.jpg`, or another size `images-api.nasa.gov/asset/<nasa_id>` lists. Only items credited to NASA: a `photographer` or `secondary_creator` from outside NASA, or a © in the description, is someone else's copyright. |
| Paintings, artefacts | `api.artic.edu/api/v1/artworks/search?q=…&fields=id,title,image_id,is_public_domain` | `https://www.artic.edu/iiif/2/<image_id>/full/843,/0/default.jpg`, only where `is_public_domain` is true. |
| Paintings, artefacts | `collectionapi.metmuseum.org/public/collection/v1/search?hasImages=true&q=…`, then `…/objects/<id>` | The object's `primaryImageSmall`, only where `isPublicDomain` is true. |
2. **Wikimedia Commons**, for anything with a name. Read the licence before using a file:
`commons.wikimedia.org/w/api.php?action=query&format=json&titles=File:<name>&prop=imageinfo&iiprop=url|extmetadata&iiurlwidth=500`
gives `thumburl` and `extmetadata.LicenseShortName`. Take only addresses under
`upload.wikimedia.org/wikipedia/commons/`: `/wikipedia/en/` and other per-language paths hold
non-free files a Wikipedia article may use and a deck may not. Thumbnails exist only at 120,
250, 330, 500, 960, 1280 and 1920 px; any other `NNNpx-` width is a blank card, so say which
width a card uses. For an SVG use its `/thumb/…/500px-….svg.png` render, since the original
never renders. The API's addresses end in a `?utm_…` query: drop it, and never build a
thumbnail address from one that still has it, which answers 400.
To search Commons rather than look up a name, ask for files whose structured data already says
they need no credit, which saves a licence lookup per file:
`…&generator=search&gsrnamespace=6&gsrsearch=<words> haswbstatement:P6216=Q19652` (public
domain) or `haswbstatement:P275=Q6938433` (CC0), with the same `prop=imageinfo` on the end.
Search one request every 3 seconds and wait out a `Retry-After`; four at once get 429.
3. **Openverse**, which searches Flickr, museums and other open collections, with no key:
`api.openverse.org/v1/images/?q=…&license=cc0,pdm` keeps to pictures that need no credit (add
`,by,by-sa` only when the credit fits, below). Each result's `url` goes on the card; its
`license` and `attribution` say what to credit. For an everyday object, add
`&source=stocksnap,rawpixel`: unfiltered results run to old scans, product shots and unrelated
photos. Anonymous use allows 20 requests a minute and 200 a day.
4. **Unsplash**, for an everyday object or scene nothing above shows: the photo's
`https://images.unsplash.com/photo-…?w=1080&fm=jpg` address, never the web page's and never
`plus.unsplash.com`, which is paid and licensed separately. The Unsplash Licence needs no
credit. Searching Unsplash needs an API key; without one the site answers with a bot check,
which is not something to work around, so use an address the user gives you or move on.
**Look at every picture before it goes on a card.** A search's first result shows the card's
fact about half the time, and its second about a quarter, so a picture nobody looked at is wrong
as often as right: when no candidate shows it, the card stays without one. For many cards, use
contact sheets: paste a few candidates per card, a handful of cards per sheet, into one image and
pick from that. It costs far less than opening pictures one by one and still catches near misses.
Keep each chosen picture against its card's `id`, never its position, which moves whenever cards
are added or reordered. Reject a single thing for a plural
word, a part standing for the whole, a brand or mascot, and alcohol on a children's deck. Fetch
from one host a few at a time; Wikimedia's thumbnails answer 429 at eight parallel requests.
**Licences.** Public domain, PDM and CC0 need nothing. CC BY and CC BY-SA need a credit, and the
deck's `--description` is the only place for one: `Pictures: <author>, <licence>, via <source>`,
per picture, within the description's 500 characters. When the credits will not fit, use a
public-domain picture for those cards or leave them without one. Never use a picture marked NC,
ND, "fair use", "all rights reserved" or with no licence at all, and never take an address from a
search engine's results, Pinterest, Instagram, or a host that forbids hotlinking (Pixabay does):
the phone fetches each picture from where it is hosted, for every learner, for as long as the deck
exists.
A host the sandbox cannot reach can still be right, because the phone fetches the picture, not
you. `--check-images` cannot vouch for those, so tell the user which URLs went unchecked.
A check can also come back with URLs it "could not check", when their host rate-limited or timed
out: that says nothing about the pictures. `loopky card check-images <deckId>` asks again over the
deck as published and writes nothing, and it is how to find pictures that have died since; its
`--json` lists `card_ids` for each bad URL, to fix with `card edit`.
## General language decks
"The essential English deck for Portuguese speakers" is a deck of thousands of cards that nobody
reads before it is published, so its shape has to be right by construction. Declare the pair, and
turn on `--listen`, `--speak`, `--type` and `--reverse` unless the user says otherwise. **Write
the title and description in the learner's language**, not the one being learned: it is what they
search in and what tells them the deck is for them.
**What the research supports, so say this much and no more.** About 3,000 word families cover
roughly 95% of spoken English, and 6,000–7,000 reach 98% (Nation 2006; van Zeeland & Schmitt
2012), which is what justifies a size. Plain word cards work: a 2020 meta-analysis (Webb,
Yanagisawa & Uchihara) found flashcards and word lists gave larger gains than writing or
fill-in-the-blank exercises. A sentence around a word is not shown to teach its meaning better
(Webb 2007; Laufer & Shmueli 1997), so a word stays a word card and phrases are added for usage,
not in its place. Recalling the language being learned from the learner's own is the stronger
direction (Nakata), which is why the front is the learner's language. "One new word per sentence"
is a rule of thumb with no controlled study behind it. Do not present anything else as research.
**Rank words from frequency data, never from memory.** Take a subtitle-based frequency list for
the language and pass it through a CEFR-graded word list, weighting by level: raw subtitle counts
are full of names, interjections and film vocabulary. Rank by lemma, so `go`, `went` and `going`
are one entry instead of three.
**Compose it as words and phrases together, and measure that before publishing.**
- **About 40% of the cards are phrases or full sentences.** Count it per 100 cards across the
first 500 and per 500 after that, not only over the whole deck: strict frequency order puts every
function word first and every phrase last, and a learner meets a word list.
- **Frequency order is the backbone, and each phrase sits right after the rarest word it uses**,
so a phrase card combines words already met.
- **Open with a block of about 75 survival phrases learned whole** — greetings, asking for
something, not understanding, numbers in use — before the ranked list starts.
- **A word with no clear one-word translation gets a short sentence, never a label.** Articles,
auxiliaries, most prepositions and inflected forms (`will`, `went`, `the`, `at`) are learned in
use: `Eu vou ligar para você → I will call you`, not `auxiliar de futuro → will`. A front that
is a grammar term is a card to rewrite.
- **Put on the front what the learner's language leaves out and the answer states**: a dropped
subject pronoun, a gender, a formality. `(ela) Está cansada → She is tired`; without the aside a
correct `He is tired` is graded wrong.
**Check the merged file, not the batches.** Cards written in separate batches or by parallel
agents collide only once they are together, so dry-run the whole file with the deck's real flags.
`card_advice` names the cards where a front appears twice, where a back does under `--reverse`,
where an aside contains a word of its own answer, and where an answer lists alternatives;
`composition` counts one-word answers against longer ones for each stretch. Fix until both are
right. Two things no dry run can see are yours to check with a script: no front is a grammar
label, and the language of each side is the one declared.
**A deck too long to show is shown as evidence.** The user cannot read 5,000 cards, so give them:
the composition per stretch (words, phrases, sentences), a random sample of about ten cards from
each stretch, and the complete list of the riskiest category — false friends in most language
pairs — which is short enough to read and is where a wrong card does the most harm.
## Decks from a TV series
"A deck from SpongeBob season 1" is a language deck: the goal is to understand the show in the
language the user watches it in, so every card comes from the show's own dialogue.
**Propose one deck per season before writing anything**, titled with the zero-padded season
first, then the show and language (`S01 · SpongeBob · Spanish`), so the deck list sorts in season
order. A season is a few hundred cards, and a deck per season lets the user stop, or start at the
season they are watching. Ask which language they watch it in and which dub: a Latin-American and
a Castilian dub use different words, and the deck's `--back-lang` (`es-MX`, `es-ES`) has to match
the one they hear. Create each deck with `--id <show>-s<n> --if-not-exists`, so re-running the
creates is safe.
**Say how many cards per episode before building, and that it is a selection**, in one sentence
such as "about 20 cards per episode, chosen for reuse, not the whole transcript". Users expect
every line otherwise. Settle the number then: `card add` appends, so a second round lands after
the whole season, and the deck walks it twice instead of episode by episode. If a later round is
added anyway, put it with its episodes with one `card reorder` (above): sort the `card list` lines
by the episode aside, keeping each episode's own order. Around 30 per episode is still a selection
for an 11-minute segment.
**Get the dialogue from subtitles in the dub's language, never from memory.** Use the user's own
`.srt` files when they have them, then try, in order:
| Source | Good for | How |
| --- | --- | --- |
| OpenSubtitles | Most shows, most languages | `rest.opensubtitles.org/search/episode-<n>/query-<show>/season-<n>/sublanguageid-<spa\|por\|fre\|ger\|jpn…>` with the header `User-Agent: TemporaryUserAgent`, no key; path segments stay in that alphabetical order, and dropping `episode-<n>` lists the season. Each result's `SubDownloadLink` (on `dl.opensubtitles.org`) is a gzipped `.srt`, often Latin-1 rather than UTF-8. Downloads stop at about 200 files a day per address: past that every `SubDownloadLink` answers 404 with an HTML page, which is the quota and not a missing file, so do not retry it that day. Searches keep working, so the episode and segment list is still there. |
| The show's fan wiki | Shows whose wiki is in the dub's language | Transcript pages (often `<Segment title>/transcript`) over the wiki's MediaWiki API: `<wiki>/api.php?action=query&format=json&prop=revisions&rvprop=content&rvslots=main&redirects=1&titles=<A>\|<B>`, several titles per request, no quota. Lines are wikitext, `{{L\|Speaker\|text}}` or `'''Speaker:''' text`, with stage directions in `''[…]''`: keep the text, drop directions, links and templates. A title the wiki spells differently turns up with `list=search&srsearch=intitle:transcript <title>`. What the voices say, not a translation. The host differs per show, so `loopky doctor` cannot list it; a wiki that answers with a bot check is not usable. |
| Addic7ed | TV episodes, mostly English | `www.addic7ed.com/search.php?search=<show>` lists `serie/<Show>/<season>/<episode>/<Title>` pages; each subtitle's `/original/…` or `/updated/…` link downloads with that page as the `Referer`. |
| Jimaku — `jimaku.cc` | Anime in Japanese | Each `jimaku.cc/entry/<id>` page links its files under `/entry/<id>/download/…`, no key. |
| Kitsunekko — `kitsunekko.net` | Anime in Japanese | `kitsunekko.net/dirlist.php?dir=subtitles%2Fjapanese%2F` lists shows; files are `.ass` or `.srt`, sometimes zipped. |
Coverage is uneven — OpenSubtitles had Spanish for three of SpongeBob's first-season segments —
so search each episode, and say which ones had nothing. For a whole show, one source for every
season beats a patchwork.
**Count the episodes before promising decks.** Searching costs nothing against a download cap, so
list every season first. When the show has more files than one day's downloads, say so in the
plan rather than after the 404s: fetch season by season, build the decks for what arrived, and
tell the user which seasons wait for tomorrow, for their own `.srt` files, or for another source
in the table: the cap is the one good reason to mix sources. A 404 after roughly 200 downloads,
or on several files in a row, is the cap, so do not send more to make sure. A single 404 early
in the day is a subtitle that was removed: take that episode's next result.
Prefer a subtitle marked as the dub's own transcript (often "SDH" or "for the hearing impaired")
over a translation of the original: a translated subtitle does not say what the voices say. Check
the episode list (season, episode number, segment title) against the show's episode guide so
episode 3 really is episode 3 — many cartoons split an episode into segments (`s1e01c - Tea at
the Treedome`), so match on the segment title. Sources spell titles differently, so compare them
normalised (lowercase, letters and digits only) and require equality: word overlap and a search's
first hit both pick the wrong episode, and keep a short hand-made list for segments known under
two titles. Say which guide the numbering follows, list its gaps, and tell the user which files
you used. `loopky doctor` lists the fixed hosts above under `recommended`; when the one you need
is blocked, ask the user to allow it, as for the required hosts. If no source is reachable or none
matches the dub, stop and ask for the files: a deck built from the wrong subtitle teaches lines
the show never says.
**Clean the lines before choosing from them.** Drop timing, speaker labels, `[sound cues]`,
cues the uploader added (an episode title card, a credit, an advertisement for a website),
`♪` song lyrics, the opening and closing theme, and character and place names on their own. Join a
sentence split across two subtitle cues. Four traps:
- **Many subtitle files are ALL CAPS** (close to half, on one show). Detect it per file and lower-case
it, restoring names and "I" when you write the card; anything that finds speaker labels by their
capitals, or keeps only lines with lowercase, silently drops those episodes.
- **Abbreviations split sentences.** Protect `Mr.`, `Mrs.`, `Dr.` and their kind before splitting
on punctuation.
- **The opening theme is not always marked with `♪`.** Cut by time: find the theme's first cue and
drop everything up to about 35 seconds after it.
- **Count the cleaned lines per episode.** A season with a few dozen lines is a broken cleaner, not
a quiet season.
**Pick what is worth learning, not the transcript.** Every deck is public, so a season's dialogue
published in order is the show's script republished. Take each episode's useful words and phrases
— the ones a learner needs to follow it and would hear again — and leave the rest. Cards go from
the user's language to the one they are learning: the front is the meaning in their language,
translated for that scene, and the back is the line or word exactly as the show says it
(`--front-lang en-US --back-lang es-MX`). The user recalls the show's words, and Speak and typing
grade them. A back may drop a leading filler or name (`Oh,`, `<Name>,`), since what is left is
still a piece of the spoken line. Nothing from outside the show: no invented example sentences,
no "related" vocabulary, and a word gets a card only in a form the episode uses. **If the user asks
for the theme song,** do not card its verses, which republishes the lyrics: card its ordinary
single words as vocabulary, with an aside such as `(theme)`.
**Order the file by episode, and never repeat.** Cards are studied new-first in file order, so
episode 1's cards come first, then episode 2's, and the user meets each episode's language before
they watch it. Within an episode, a word before the phrases that use it. A line or word already
carded in an earlier episode or an earlier season's deck is not carded again; compare ignoring
case, punctuation and `...`. The published decks are the record of what is carded, and
`loopky card list <deckId>` prints one card a line, `id<TAB>front<TAB>back` (a picture adds
` [img:…]` to its side), so it covers every season even after your working files are gone. Put
the episode on the front as an aside, `I'm ready! (S1E1) → ¡Estoy listo!`: the reader sees where
it comes from, and nothing grades it. Publish the first episodes with `deck create`, and add later
ones in order with `card add <deckId> --from-file`, which appends.
**A whole show is a pipeline: filter, brief, check, then de-duplicate.**
1. **Filter before any model reads anything.** Keep complete sentences of one to seven words,
de-duplicated per episode, minus pure interjections and everything already published. That
leaves about 100–250 candidates an episode; the full dialogue stays available for context.
2. **One agent per season, in parallel, with a written brief:** what to pick and skip, the exact
file format, the per-episode count, whether a back may drop a leading filler, and to report a
checker that looks wrong rather than bend a card to fit it.
3. **Give them a checker script, and make "prints OK" the exit condition.** It confirms that every
back appears in that episode's dialogue ignoring case and punctuation, the episode aside is well
formed, no back holds brackets or slashes, nothing repeats in the season or is already
published, and the count is in range, with a lower bound that lets a thin episode come in short
rather than padded. This is what makes "nothing from outside the show" enforceable. Test it on
lines you know are genuine first: turn newlines and punctuation into a space, never into
nothing, or `was...just` glues into one word and a real line fails.
4. **De-duplicate across seasons afterwards, in season order.** Parallel agents cannot see each
other's output, so later seasons shrink; with the published backs filtered out in step 1 the
repeats are few, without it about a third. Tell the user to expect smaller later seasons.
**Pictures from the episode only when their licence allows it, which is rarely.** Stills, frames
and screenshots of a commercial show are the studio's copyright, and fan wikis host them as fair
use, which the licence rules above exclude; a frame from the user's own copy would be an upload,
and Loopky takes only URLs. So an episode picture is limited to shows whose frames are public
domain or freely licensed on Wikimedia Commons (some early cartoons). Otherwise picture what a
word card names — an object, an animal, a place — from the usual sources, or leave it without one;
phrase cards stay bare. Real-life counterparts of the show's world (the animals and objects it is
built on) make good covers. Tell the user which it was. To add pictures to cards already
published, read `loopky card list <deckId> --json --missing-image` once, match each card on its
back text, and send the pictures in one JSONL `card edit --from-file`, each line naming the card's
`id` and its `front_image_url`. Add the same URLs to your card file: `card add` tells cards apart
by text and picture, so re-running a file without them adds those cards a second time.
**Tags and settings.** Add the show's name (lowercase, no spaces, at most 20 characters:
`spongebob`), and `tv-series` or `anime`, plus `cartoon` where it is one. A show made for children
also gets `kids`. The language pair adds the language tags on its own. Turn on `--listen` and
`--speak`, so the user hears and says the lines, and `--type` when they want to spell them; a
listening deck for a child who cannot spell yet works best with `--reverse` on and `--type` off.
A children's description reads well as a hook line, two lines about the season, then how to
study, each on its own line with an emoji.
## Limits worth knowing
- The session can write only Loopky's own data (`/pub/loopky/`). It cannot post, follow or edit a
profile, and widening that is not an option.
- Published decks are public. There are no private decks.
- With the CLI, a headless box with nobody at a phone can use `LOOPKY_SESSION`, minted with
`loopky login --export` on a machine where the user can approve. It is a bearer token: never echo
it, log it or commit it.
## Reporting friction to Loopky
Loopky improves from what agents trip over, and only the user can decide to tell the project. So
when the work is done, and only if this session hit **real friction in `loopky` or this skill**, ask
once whether to open a GitHub issue on `jvsena42/loopky`. Friction is: an error or exit code that
misled you, a step here that was wrong or missing, a flag or command you needed and the binary did
not have, a workaround you had to invent, or output you could not parse. It is **not** the user's
own network allowlist, a session expiring after its hour, a picture source with nothing fitting, or
anything the exit-code table already says how to handle. No real friction, no question.
1. **Ask only at the end, and collect nothing until the user says yes.** Never mid-task, not even
right after the friction happens: finish what the user asked, verify it, and make this the last
thing in your final message. In one short question, name the problem in general words
("`card add` failed on a newline"), say it would become a public issue on `jvsena42/loopky`,
and ask whether they want one. Leave the rest for after a yes. Until they say yes, run nothing
for it, check no GitHub account, and write no draft. A no, or no answer, ends it for the rest
of the session.
2. **After a yes, gather only what reproduces the problem:** `loopky --version` (or, through the
connector, the tool's name instead), the OS and architecture, the command's shape with every operand replaced by a placeholder, the exit code
and `error.code`, what you expected, what happened, and the workaround if there was one.
3. **Keep the user's data out.** The issue is public, so it never carries card or deck content,
titles, descriptions or tags, deck or card ids, public keys, `pubky://` addresses, image or
homeserver URLs, file or directory names, user, host or machine names, IP addresses, the
`auth_url`, `LOOPKY_SESSION` or any other token, environment variables, or anything the user
said about themselves. Describe error messages in your own words rather than pasting them,
since they can carry ids and paths. Re-read the draft against this list before showing it.
If the problem cannot be explained without one of these, leave it out and say so.
4. **Show the draft, title and body, and file it only after the user approves that text.** If the
session has a signed-in GitHub tool (`gh auth status` succeeds, or a GitHub connector is
available), use it, searching the repository's open issues first and adding to a matching one
rather than opening a duplicate:
```shell
gh issue create --repo jvsena42/loopky --title "<title>" --body-file <draft file>
```
The draft file is a temporary one; delete it afterwards. Otherwise, or if they prefer, give
them the link to file it themselves, `https://github.com/jvsena42/loopky/issues/new`, with the
draft to paste. Issues are public, and are filed from the user's own account.
Wersje
W bazie nie ma innych skilli o nazwie loopky.
Migawka bazy z 28.10.2026 · wersja paczki c4ebe785a06c (skrót SHA-256 całej paczki)
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 100anki
Tworzy fiszki Anki, dodaje notatki, zarządza taliami i pomaga w nauce metodą powtórek w odstępach. - 100kotoba
Generuje gotowe do importu talie Anki (.apkg) do nauki języków z opisu: planuje talię w rozmowie, tworzy fiszki ze słownictwem, czytaniem, definicją, zdaniem, tłumaczeniem, audio TTS i obrazem oraz waliduje paczkę. - 100anki
Tworzy talie i dodaje fiszki na koncie AnkiWeb z wiersza poleceń oraz wypisuje istniejące talie i typy notatek. - 100flashcard-generator
Zamienia notatki, artykuły lub temat w fiszki do powtórek w odstępach: atomowe, z lukami cloze i aktywnym przypominaniem, gotowe do importu do Anki. - 100anki-card-maker
Wyciąga kluczową wiedzę z notatek i materiałów do nauki i generuje fiszki pytanie-odpowiedź w pliku CSV do importu w Anki. - 100making-flashcards
Zamienia pomysły z rozmowy, notatek lub tematu badań w fiszki Anki według reguł użytkownika, sprawdza duplikaty w lokalnej kolekcji Anki i zapisuje importowalny plik TSV w ~/Downloads.