Skip to content

List and download a profile's LSI, from the library and the CLI - #59

Merged
sadit merged 2 commits into
mainfrom
lsi-download
Sep 25, 2026
Merged

sadit merged 2 commits into
mainfrom
lsi-download

Conversation

@sadit

@sadit sadit commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Each profile in profiles-1.1 has its LSI beside it as <nickname>-lsi.zip, but list_remote_profiles hides them on purpose (#51), so the only way to get one was to build the URL by hand. This adds the missing path, in the library first and the CLI on top of it.

Library

  • list_remote_lsi(; repo, tag, url): the release's LSIs, in the same shape as list_remote_profiles. name is the nickname of the profile each one belongs to ("es" for es-lsi.zip).
  • download_lsi(nick; repo, tag, dest, url, force): downloads <nick>-lsi.zip into ~/.textsearch/lsi/<nick>.zip, apart from profiles/ because it is not a profile. It checks nothing itself; load_lsi is still the one that refuses a wrong profile.
  • lsi_summary(path): (profile_id, name, repo, tag, outdim, maxoutdim, scaling) read from the manifest, without loading the projection. That makes the binding check cheap (a manifest read against dequantizing up to 300 MB).
  • Listing and downloading share a single implementation for profiles and LSIs, and file:// counts as a direct URL, as the app already treated it.
p = load_profile(download_profile("es"))
lsi = load_lsi(download_lsi("es"), p; outdim=64)

CLI

LSIs are listed beside the profiles, in their own section, and every management command handles them:

$ textsearch list --remote
Remote profiles (sadit/TextSearch.jl @ profiles-1.1):
  en (50.5 MB) -> …/en.zip
  …
Remote LSI projections (sadit/TextSearch.jl @ profiles-1.1):
  en (297.1 MB) -> …/en-lsi.zip
  …
command what it does with the LSI
list / list --remote two sections, profiles and LSI; --profiles / --lsi narrow it. Locally it flags an LSI not bound to its profile, or whose profile isn't installed
download es --lsi profile + LSI; keeps an already-installed profile. Checks the profile_id: if the LSI names another profile, it removes it and says so
install ./es-lsi.zip recognizes an LSI by its manifest and installs it into lsi/ as es. Refuses it if the installed es isn't the profile it was fitted against; with no profile it's accepted and list shows it as waiting. Replacing a profile the installed LSI no longer matches prints a note
info es new line: lsi: installed, outdim=256 -> …, or bound to another / not installed
info es --lsi, or info <path to an LSI> the LSI itself: profile it names (id, repo @ tag), whether it's installed and bound, outdim, scaling
uninstall es [--force] removes the profile and its LSI (one without its profile can't be loaded); --lsi removes only the LSI

Why the refusals: an LSI against the wrong profile doesn't fail, it answers wrongly, so it can't be left installed where a consumer would load it.

Verified

  • Against the real release (TEXTSEARCH_HOME sandboxed): list --remote shows the 7 profiles and the 7 LSIs in separate sections. download eu, install eu-lsi.zip, list, info eu --lsi, info <path>, uninstall eu --lsi [--force], download eu --lsi and uninstall eu --force behave as described.
  • App: 279/279 tests pass. The new ones need no network: a local release over file://, with an LSI bound to another profile. They cover the list sections, download --lsi, install (bound, refused, waiting for its profile), info --lsi / on a path, and uninstall with and without --lsi.
  • Library: the full suite passes, Aqua included. New tests: lsi_summary (directory and zip), download_lsi (lsi/ destination, force), and list_remote_lsi on the mock.
  • Tutorial and app README updated.

🤖 Generated with Claude Code

sadit and others added 2 commits September 24, 2026 15:46
A release carries each profile's LSI projection as <nickname>-lsi.zip, and
list_remote_profiles hides those on purpose, so the only way to get one was
to build its URL by hand.

Library:
- list_remote_lsi(): the release's LSI assets, named after their profile.
- download_lsi(nick): fetches <nick>-lsi.zip into ~/.textsearch/lsi/,
  apart from profiles/.
- lsi_summary(path): what an artifact says about itself (profile_id,
  outdim, ...) from the manifest, without dequantizing the projection.
- Listing and downloading now share one implementation for both kinds, and
  a file:// URL counts as direct, as the app already treated it.

CLI:
- list --lsi / list --remote --lsi.
- download NICK --lsi: also fetches the LSI (keeping an installed profile)
  and removes it again if it is not bound to that profile.
- info reports the installed LSI and whether it is bound; uninstall takes
  it with the profile.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
list shows installed profiles and LSI projections in two sections, and
--remote does the same for a release; --profiles/--lsi narrow it. An LSI
is flagged when it is not bound to its nickname's installed profile, or
when that profile is not installed.

install recognizes an LSI zip by its manifest, installs it into lsi/
named without the -lsi suffix, and refuses it when the installed profile
of that nickname is not the one it was fitted against. Replacing a
profile that its installed LSI no longer matches prints a note.

info NICK --lsi, or info on a path to an LSI, shows the profile it names,
whether that profile is installed and bound, outdim and scaling.

uninstall --lsi removes only the LSI.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@sadit
sadit merged commit bb80a59 into main Sep 25, 2026
4 of 5 checks passed
sadit referenced this pull request Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant