Skip to content

CACCHT Explorer (cfabric-browser): reading, searching and comparing corpora - #18

Merged
MartijnNaaijer merged 113 commits into
masterfrom
browser-rust
Nov 2, 2026
Merged

MartijnNaaijer merged 113 commits into
masterfrom
browser-rust

Conversation

@MartijnNaaijer

Copy link
Copy Markdown
Contributor

Adds CACCHT Explorer (package cfabric-browser, in libs/explorer). It is the successor of the Text-Fabric browser: a FastAPI server with a React interface for reading, searching and comparing corpora side by side, offline. It also runs as a standalone program for Windows, macOS and Linux. The program has been tried as a series of pre-releases, from desktop-v0.1.0-test.1 to desktop-v0.1.0-test.16.

This is a draft: a few things need agreement first (see To agree on below). It is 112 commits, built on a chain of branches (browser-phase1 → browser-parallel → browser-interfaces → browser-jps → browser-downloads → browser-bdb → browser-rust). If you'd rather review it in parts, I can split it along that chain.

What it does

  • Five interfaces, one bundle, switching between them keeps the passage, corpora and search:
    • Panes: synchronised reading per pane.
    • Parallel: verse-aligned columns.
    • Reader: chapters with a side panel.
    • Interlinear: lines per word, such as transliteration, gloss and morphology.
    • Concordance: keyword in context, with facets, collocations and statistics.
  • Comparing: consonantal differences between the MT (BHSA), the SP and the Dead Sea Scrolls, per scroll, with three-way agreement. Reconstructed DSS text is dimmed and never counts.
  • Searching: TF search templates in worker processes, with cancel, timeout, result cap and streamed results. Results can be exported as TSV or Excel, with statistics.
  • Lexicon: the BHSA's lexemes, with occurrences and distribution. It shows the BDB entry when the dictionary is added; the dictionary is published as Context-Fabric/bdb v1.0, CC BY-NC 4.0.
  • Translations: the JPS 1917, built locally from Sefaria's export into an ordinary CF corpus (cfabric-browser add jps1917).
  • Downloads: the BHSA, SP and DSS from their own GitHub releases, pinned by checksum, in the program or with cfabric-browser download.
  • Asking in your own words: the Explorer is an MCP server (/mcp, and cfabric-browser mcp over stdio, also as a Claude Desktop extension). An AI app such as Claude or ChatGPT writes a search template and proposes it; the user sees it and runs it. Results always come from the CF search engine. Tools are shared with cfabric-mcp. A BHSA guide with 42 worked examples comes with it.
  • User guide: eleven chapters with screenshots, in the program at /guide/ and on caccht.github.io /explorer/.

Works on either core

The Explorer uses only the public API, so it runs on the Python core (0.5) and on the Rust core (context-fabric==0.6.0rc1). Since browser-rust, a few pieces that used to be added to the core live in the Explorer instead: display (render trees, a port of TF's tf.advanced without HTML), the corpus registry and cancellation. Searches go through S.search, and the worker process checks for cancellation between results. The standalone program is built on 0.6.0rc1.

Changes outside libs/explorer

  • libs/core:
    • T.sectionFeatureTypes was str for every level on the first load from .tf files, so references like Genesis 1:1 failed in that session.
    • The S.search/S.fetch docstrings had limit the wrong way round.
    • Both are listed under Unreleased in the CHANGELOG.
  • libs/mcp:
    • tools.using(registry) lets the tools run on another registry of corpora, here the Explorer's.
    • search_syntax_guide("quantifiers") explained /where/ … /have/ wrongly.
    • Both are listed under Unreleased in the CHANGELOG.
  • .github/workflows/ci.yml: a test-browser job with a matrix core: [python, rust].
  • .github/workflows/publish.yml: browser-v* tags publish cfabric-browser to PyPI. The job checks that the built interface is in the wheel.
  • .github/workflows/browser-desktop.yml builds the standalone program on Windows, macOS (arm64 and x64) and Linux, and runs five packaging tests on each: smoke, translation, download, dictionary and MCP. desktop-v* tags publish a GitHub pre-release.
  • .gitignore: .cfr/ (the Rust core's cache) and the built interface (libs/explorer/cfabric_browser/static/).
  • site/: a docs page Explorer (/docs/explorer).

To agree on

  1. The Explorer on 0.6. Do we release it alongside context-fabric 0.6.0, and keep it working on 0.5 for now?
  2. The explorer extra in the Rust core's pyproject.toml: explorer = ["cfabric-browser[window]"]. Then pip install "context-fabric[explorer,mcp]" gives everything. This belongs on cf-rust, not in this PR.
  3. cfabric-mcp 0.2 with tools.using. The Explorer needs it, but its requirement still says cfabric-mcp>=0.1.7, which lacks it. That requirement should become >=0.2 once 0.2 is out.
  4. Release order: cfabric-mcp 0.2, then cfabric-browser 0.1.0 (never published yet), then context-fabric 0.6.0 with the extras. After that, try pip install in clean environments on all platforms in CI.

Tests

  • Explorer: 408 Python tests (cd libs/explorer && pytest tests) and the frontend's Vitest tests (npm test). npm run build type-checks.
    • The Python tests use small fixtures (tests/fixtures/) and corpora written in temporary directories; no real corpora or network are needed.
    • CFABRIC_REAL_CORPORA=1 adds a question set of 30 BHSA requests for the AI search guide.
  • CI: this PR is the first time ci.yml runs on this work. The branches only ran browser-desktop.yml, which is green on all four platforms for this commit.

Trying it

pip install -e libs/core -e libs/mcp -e "libs/explorer[window]"
cd libs/explorer/frontend && npm ci && npm run build && cd -
cfabric-browser download bhsa sp dss      # or start empty and download from the library
cfabric-browser --window                  # or open http://127.0.0.1:8107 without --window

Or download a standalone program from the latest pre-release, desktop-v0.1.0-test.16.

🤖 Generated with Claude Code

MartijnNaaijer and others added 30 commits October 27, 2026 16:22
S.search() and S.study() accept a CancelToken (or a timeout shorthand).
The engine checks the token between study phases, while spinning atoms
and edges, inside quantifier sub-searches, and once per candidate of the
outermost stitching loop, raising SearchCancelled / SearchTimeout.

This is groundwork for the browser, which must be able to stop runaway
queries. Also corrects the docstrings that said a generator is returned
when a limit is given; it is the other way round.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CorpusRegistry holds named corpora, loads each at most once (also under
concurrent access), supports lazy loading via register(), and exposes a
per-corpus search lock, since S keeps per-query state on the Api.

The MCP CorpusManager now subclasses it, keeping its existing behaviour
that load() replaces a corpus of the same name. The browser will share
the same registry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The display layer that Context-Fabric was missing compared to TF's
tf.advanced, without any HTML:

- DisplayConfig reads a corpus' TF app config.yaml (found next to the
  data) and computes TF's defaults for whatever it leaves open: levels,
  labels, feature lists, hidden/base/condense types, writing direction,
  section separators, none values, provenance.
- unravel/render_node/render_tuple build render trees: the nested
  fragments of a node, cut at the boundaries of other nodes, dressed
  with labels, texts, section headings, features and highlights, and
  serialisable to JSON for the browser.
- section_ref/node_from_section_ref handle references like Genesis 1:1
  with the corpus' own separators.

The unravel algorithm is a port of tf.advanced.unravel. Checked against
TF on 3944 random nodes (all types, pretty/plain, folded/unfolded) of
BHSA, DSS, LXX, CUC, Descartes and Peshitta: all trees identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new package, libs/browser, with the server half of the Context-Fabric
browser (phase 1 of the browser plan):

- cfabric-browser command: corpora by name (bhsa, ETCBC/dss), TF-layout
  repository or data directory; binds to 127.0.0.1.
- FastAPI JSON API: corpus cards, features, section tree, passages and
  nodes as render trees, node inspector, template check, search with
  server-sent status events, paging, results in context, TSV export.
  Endpoints mirror the MCP tools where they overlap; no server paths are
  exposed.
- SearchPool: searches in spawn-based worker processes that share the
  memory-mapped corpora. Parallel, cancellable (cooperative token, with a
  watchdog that restarts unresponsive workers), time limits, result cap,
  streaming batches, canonical sort when done.
- Structured template problems (line, message, feature/type). Problems
  inside quantifiers are only logged by the engine (as in TF), which
  then returns results as if the quantifier excluded nothing; the
  browser reports them as errors instead.

The interface (a Vite/React app) follows; until it is built, / shows a
placeholder and the API docs are at /docs. CI gets a test-browser job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Vite + React + TypeScript interface for cfabric-browser, built into
cfabric_browser/static (not in git; CI and the release workflow build
it, and the publish job checks it is in the wheel).

- Read: book and chapter navigator, passages as running text or as
  structure (pretty display), previous/next across chapters, opens at
  the start of the corpus; right-to-left text set in its own script.
- Search: CodeMirror editor for TF templates with highlighting,
  autocomplete of types and features, and live error marking; live
  status with Stop; virtualised result list that loads pages as you
  scroll; results unfold in context with hits gilded (deeper gold for a
  hit inside a hit); recent searches; TSV download.
- Inspector: all features of a node (empty values and internal features
  summarised), relations, what it lies in and contains.
- Pretty displays draw render-tree edges with meaning: solid where a
  node starts or ends, dashed at a gap, open where it continues.
- State in the URL (corpus, view, passage, template, search, result);
  display preferences per browser; light and dark themes; works at
  phone width.
- Fonts bundled for offline use (Source Serif 4, JetBrains Mono, Noto
  Serif Hebrew, Gentium Plus, Noto Sans Syriac, Amiri); Ezra SIL or SBL
  Hebrew are used when installed.

Server changes: passages report their section path and previous/next
sections; the node inspector leaves out omap@ version-mapping edges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The results TSV gets, per node of a result, a column for each feature
mentioned on that node's line of the template; `sp*` adds a feature
without narrowing the search, as in Text-Fabric. `?excel=true` writes
UTF-16 with a byte-order mark, which Excel opens with Hebrew and other
scripts intact. The interface offers both downloads and explains the
`feature*` trick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a corpus is loaded from .tf files (its first load, before the .cfm
cache exists), feature metadata uses TF's `valueType` key, but Text read
only the .cfm key `value_type`. Every section level was then typed `str`,
so references such as "Genesis 1:1" could not be resolved to nodes in that
session. Read both keys; the regression test loads a fresh copy twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Book concordance (books.py): book names across corpora mapped to OSIS
  ids (1_Samuel, 1Sam, Samuel_1, ...). Only safe mappings: e.g. the LXX's
  2Esdr (Ezra + Nehemiah) and Theodotion's Daniel are not mapped.
- GET /api/corpora/{c}/align?from=&ref=: the counterpart of a passage in
  another corpus, falling back to the enclosing chapter (exact: false)
  when a verse is missing there, as with 1 Sam 17:12 in the LXX.
  Verses are matched by number; versification differences (e.g. the
  Psalms in the LXX) are not corrected yet.
- Library: GET /api/library lists corpora found under ~/text-fabric-data
  and ~/github; POST /api/corpora opens one by library id (never by
  path) and tells the search workers about it. --no-library switches
  this off for servers reachable by others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Workspace of up to four panes side by side, each with its own corpus,
  view, passage, template and search; all in the URL (c0, v0, ref0, ...),
  and older single-view links still open as the first pane.
- Sync passages: opening a passage in one pane opens the corresponding
  passage in the other reading panes via the alignment API, with a note
  when only the chapter exists there (e.g. 1 Sam 17:12 in the LXX).
- Open a corpus: a library dialog lists corpora found on this computer
  and opens one in a new pane.
- Search all corpora: runs the template in every open corpus, shows the
  live count per corpus (or why the template does not fit), and opens
  any of them in its own pane.
- Narrow panes fold the passage list away and put the search editor
  above the results; result rows no longer repeat a verse heading as
  text when the reference column already shows it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`DT-UCPH/sp@7.2.4` loads that version, `sp@latest` the newest on this
computer; without `@` the version named in the corpus' app config is
used, as before. Asking for a version that is not on disk lists the
versions that are. The library's open endpoint accepts the same syntax,
and the corpus card now reports the data version actually loaded rather
than the app config's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings in ~/.cfabric/display/<org>/<repo>.yaml, or for one version
<repo>@<version>.yaml, are merged over the corpus' Text-Fabric app
config. This covers corpora whose app config lags behind their data
(SP 7.2.4 has clause and phrase layers that its app config does not
describe yet) without editing downloaded files, which Text-Fabric
replaces on updates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Results / Statistics switch in the search view. Statistics count, over
the results (or the results so far while a search runs):

- the values of a feature on one part of the result tuples, by distinct
  node; by default a feature the template leaves open (`lex*`) rather
  than one it fixes (`sp=verb`); "no value" and the long tail are shown
  as muted bars;
- the results per book or chapter, in text order, by the section of
  each result's first slot (so nodes that cross sections still count);
  bars link to the passage.

Charts are single-series horizontal bars in a chart blue derived from
woad and checked for lightness, chroma and contrast in both themes, with
counts at the tips and a table view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
export.tsv takes `extra=<part>:<feature>,...` (repeatable) to add feature
columns for one part of the results, after the features the template
mentions; unknown parts or features are refused. In the interface, the
two download links become a "Download..." dialog listing the features of
each part (template features ticked and fixed), with a filter, and a
choice between TSV and TSV for Excel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Workspaces menu: save the current workspace (its URL: panes, corpora,
  passages, templates, sync) under a name in this browser; open or
  delete saved ones; export to and import from .cfabric.json files.
- Import also accepts Text-Fabric browser job files: the query opens in
  a search pane and runs, the first section in a reading pane, provided
  the job's corpus is open (otherwise it says which one to open).
- Panes rerun their template when the server no longer knows their
  search id (searches live in server memory), so saved workspaces and
  shared links keep working after a restart.
- The top bar wraps its buttons to a second row on narrow screens
  instead of breaking their labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After `sp=` (or `sp=verb|`) the editor offers the values that occur,
most frequent first, with their counts. Hovering a feature name shows
its description, the object types it is on, how many values it has and
the most frequent ones; hovering an object type shows its count.
Feature descriptions come from the existing feature endpoint and are
cached per corpus. Tooltips are built with textContent only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A "Cite" button in the reading header and in the search status line
opens a citation to copy: the passage, or the search template with its
number of results; the corpus with title, version and DOI; and the
browser and context-fabric versions with the date. /api/health now
reports the installed context-fabric version for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Copies of one corpus (same app title, e.g. DT-UCPH/sp and its fork
  saulocantanhede/sp, or DT-UCPH/cuc and cuc_) are listed once, keeping
  the one with the newest data; the others are named as copies and can
  still be opened by id.
- Each entry carries the version that opening it loads, and the dialog
  shows that one instead of the newest on disk.
- Corpora can be hidden from the list with `library: hide:` in
  ~/.cfabric/browser.yaml or with --hide ORG/REPO.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Where slots are below word level (SP, DSS), a click in the plain text
opened the sign under the cursor. Now the base-type fragment (word) is
the click target, and base words in the pretty view are clickable too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With "Show differences" on, reading panes are compared with the first
one, verse by verse, on their consonants (g_cons_utf8, or the letters of
the original-script text). Vowels, accents and word division don't
count. Words that differ only in matres lectionis are marked as
spelling, other differences as variants; a plus is marked in the text
that has it. New endpoint: GET /api/compare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DSS has no book, chapter or verse sections; its biblical words carry
book/chapter/verse features. A book index turns these into a second way
to read the corpus: per verse, the words of each scroll that contains it.
New endpoints /books and /witnesses; align can target the book view.
Reconstructed signs are flagged so the client can dim them, and text the
DSS also lists as non-biblical (biblical=2) is labelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A DSS reading pane gets a "Scrolls | Bible books" switch. In book view
the navigator lists the biblical books and chapters, and each verse shows
the text of every scroll that contains it, with reconstructed text dimmed
and a label for text also listed as non-biblical. A scroll name opens its
fragment in the scroll view. Synchronised reading aligns book view panes
with MT and SP. The pane's choice is kept in the URL (by1=books).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With "Show differences", a DSS pane in book view is compared scroll by
scroll with the MT or SP pane. Reconstructed letters keep the texts
aligned but never count, and letters a fragment lacks count only between
two preserved letters, not where the text is lost at an edge or next to a
reconstruction. The MT/SP pane marks a word where any scroll differs,
with a tooltip naming the scrolls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DSS transcription has placeholder signs: ε (type missing) for lost
text that is not reconstructed, and # and ? (type unc) for letters too
damaged to read. They are now shown as […] and ◦, also in the scroll
view, and the book view explains them. In comparisons with MT and SP an
illegible letter counts as unknown, so MT is not marked against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DSS transcription marks morpheme breaks with a sign of its own
(type sep, ׳), as in עמ׳י. They are not in the scrolls, so the browser
no longer shows them, in the book view and the scroll view alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With MT, SP and a DSS pane in book view open, each place where MT and SP
differ is read in every scroll that has the verse, between two preserved
anchor letters: the scroll agrees with MT, with SP, or with neither, or
is left out where its text is lost or reconstructed. Differences in the
same words are one place, so a scroll reading מארות against MT מארת and
SP מאורות agrees with neither. The DSS pane lists the places per verse
with a chip per scroll; the marked words get tooltips. New endpoint
/api/agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Sync passages on, a reading pane that has no passage yet (a short
link that names the passage only once, or a newly added pane) opens the
counterpart of the first pane that has one, so links like
?c0=bhsa&ref0=Deuteronomy+5&c1=sp&c2=dss&by2=books&sync=1 work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MartijnNaaijer and others added 20 commits October 27, 2026 16:30
…th screenshots made by a script

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… moves from the release notes to the guide

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned; Reader's panel no longer covers the menus

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…elling in the lexicon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… their vowels

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he guide, a release checklist, and a test that the guide's labels exist

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itself, read-only tools, the app's name on proposals

- cfabric-browser mcp answers initialize, ping and the lists of tools,
  prompts and resources from the same server definition, and finds or
  starts the Explorer in the background; only a tool call waits for it
  (Codex gives a server 10 seconds to start).
- All tools but propose_search carry readOnlyHint, so apps ask only for
  the proposal.
- A proposal without model is named after the app (clientInfo.name via
  X-Cfabric-Client from the helper and the Claude Desktop extension, or
  the User-Agent).
- A trial that runs out of time says how to narrow the template.

Phase 2 of chatgpt-plan.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rrectly

- scripts/ask_questions.py asks Claude Code (claude -p) or Codex
  (codex exec) each request of the question set through a running
  Explorer, runs each proposal in full and scores it. Claude: 30 of 30.
- An atom under /have/ is a new one, so /where/ word /have/ word sp=nmpr
  only asks that one proper name exists. The BHSA guide, the user guide
  (Searching) and cfabric-mcp's syntax guide now name the atom
  (w:word ... w sp=nmpr) and give the /without/ form; the subjects of
  proper names only are 5,893, not 10,484.
- Question set: 29 had the same mistake (22,447), 27 counted pairs of
  words instead of verses (60); `also` holds other right readings
  (15, 26, 28), checked against the BHSA like the rest.
- README: connecting the ChatGPT desktop app and Codex; the runner.

Phase 3 of chatgpt-plan.md (Claude side).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chapter on asking Claude says how to connect the ChatGPT desktop app
(Settings → MCP servers, STDIO, the program with mcp) and Codex (codex
mcp add), with a longer tool_timeout_sec for the first question, and that
ChatGPT on the web and phones can't reach the program. Release notes:
asking ChatGPT, the corrected "only proper names" example, the helper
that no longer gives up while the Explorer starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The desktop app's Add server form may have no field for arguments, and the
Mac program's path has a space, so the guide now gives the address
(Streamable HTTP, http://127.0.0.1:8107/mcp) and codex mcp add --url;
the config.toml block with command, args and tool_timeout_sec for letting
ChatGPT start the Explorer, with the Mac path and how to open ~/.codex;
that the desktop app may offer it only when working with Codex; and the
sentence about waiting longer rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server: refuse requests from other web sites and foreign host names
(guard.py); the search watchdog no longer hands a queued search to the
worker it ends or overwrites a finished search, and a corpus that fails
to load no longer restarts workers without end; /api/corpora no longer
waits for a corpus being prepared; translation builds keep the old one
when they fail and replace only their own folder, and the library skips
half-built folders; partial downloads are removed; the stdio helper
waits before starting the Explorer again; the lexicon's caches are
locked.

Interface: the Reader shows the right chapter after > then <; Reader,
Interlinear and Concordance no longer hang on a corpus that isn't open;
the Interlinear scrolls to the URL's verse once; the first page after a
change of order or search is fetched directly; search history and pane
state no longer carry over; a failed interface switch says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The secret in ~/.cfabric/running.json protected only POST /api/proposals,
not /mcp as its documentation said. Other web sites are now kept out of
all routes by guard.py, and a secret that changes at every start can't
be given to apps that connect by address. running.json keeps the
address; the screenshot script no longer needs CFABRIC_SECRET.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Interface: Panes and the template editor load when first shown (278 kB
at the start instead of 792 kB); the hovered word lives in a small store
that only the card follows, so the text isn't drawn again on every
hover; corpus data stays fresh once fetched (staleTime), while searches,
the library and jobs are still asked again when shown.

Server: the Concordance is extended with new results instead of rebuilt
per batch; innermost nodes are found from node spans instead of slot
sets (book/word: 110 s -> 0.2 s for 3,000 results), shared with Parallel's
search results (Spans); the three-way comparison aligns each scroll once
per verse; the DSS book index asks for scroll names once per scroll
(7.7 s -> 1.3 s); per-corpus indexes are built once for requests that
come together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
api.py was one function of about 1,700 lines. Its routes now live in
cfabric_browser/routes/ (library, reading, parallel, search, proposals,
lexicon), each a build(ctx) on the shared Context in routes/common.py,
with their bodies unchanged. The OpenAPI schema is identical (54
operations, same parameters and docs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…times

net.py: certificates, requests under the browser's name, checksums and
the checked download with retry, for corpus downloads, translations and
dictionaries (three copies before; translations' private _ssl_context
was imported across packages).

words.py: the word type, the words of a node, the text format in the
original script, and BookSpans (the book of a word by bisection), for
the comparison, the Concordance, the Interlinear and the lexicon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frontend: useUrlState replaces five copies of the URL-state code (and no
longer writes the history inside a state updater); useHealth replaces
four raw fetches of /api/health; useCloseOutside replaces six copies of
the close-on-click-outside/Escape effect; corpus cards are fetched once
per corpus (corpusCard on one shared queryClient), also when switching
interfaces; openReference and Tree, unused, are gone.

Server: CorpusRegistry keeps register, get, get_api, list_corpora and
current, what the browser and cfabric-mcp's tools use. Tests of the
search pool for cancelling queued and running searches and for which
finished searches are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
caccht-explorer is the same command as cfabric-browser under the app's
name. The extra desktop is split into window (pywebview, certifi) and
build (also PyInstaller), so that context-fabric[explorer] can depend on
cfabric-browser[window] without bringing PyInstaller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
context-fabric Ready Ready Preview Oct 27, 2026 4:28pm UTC

Request Review

@codykingham codykingham left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR offers a valuable addition with the explorer application, along with several CF bugfixes. LGTM!

@MartijnNaaijer
MartijnNaaijer marked this pull request as ready for review November 2, 2026 15:26
@MartijnNaaijer
MartijnNaaijer merged commit 55c4eac into master Nov 2, 2026
13 checks passed
@MartijnNaaijer
MartijnNaaijer deleted the browser-rust branch November 2, 2026 16:02
tonyjurg pushed a commit to tonyjurg/FORK_context-fabric that referenced this pull request Nov 2, 2026
The ruleset on master (since 2026-10-28) only accepts changes through pull
requests, so the bot's direct push after merging Context-Fabric#18 was refused. The
regenerated docs now go to the branch auto/api-docs with a pull request,
which later runs update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — f3933156 Deployed Oct 27, 2026 by vercel[bot]
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.

2 participants