bible-buddy-web

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
回應語言:一律使用台灣繁體中文。
回應語言:一律使用台灣繁體中文。

Bible Buddy ELI5 — 網頁查經

Bible Buddy ELI5 — 網頁查經

A local reading desk for scripture. It loads a passage from FHL, drops plain-language notes onto the words themselves, and lets a
/bible-buddy
agent verify or expand any of them through a custom tool.
Single user, single machine, by design. State is a module-level dict, notes autosave to one JSON per passage on the Desktop, one event queue serves one reader. It binds loopback only. Don't put it behind a shared port.
本機聖經閱讀平台。可從FHL載入經文、在經文字詞上添加淺白易懂的筆記,並透過自訂工具讓
/bible-buddy
agent驗證或擴展任何筆記。
設計為單使用者、單機器使用。 狀態儲存於模組層級字典,筆記會自動儲存到桌面每篇經文對應的一個JSON檔案,一個事件佇列服務一個閱讀者。僅綁定環回位址,請勿將其置於共用連接埠後方。

Path Resolution

路徑解析

Resolve
{WEB}
to this skill's own installation directory. First path that has
server.py
:
  1. .claude/skills/bible-buddy-web/
  2. ~/.claude/skills/bible-buddy-web/
  3. bible-buddy-web/
    (relative to CWD, development)
{WEB}
解析為此技能的安裝目錄。優先選擇包含
server.py
的路徑:
  1. .claude/skills/bible-buddy-web/
  2. ~/.claude/skills/bible-buddy-web/
  3. bible-buddy-web/
    (相對於當前工作目錄,開發環境)

Prerequisites

先決條件

uv
must be installed (
which uv
). If missing, stop and tell the user: 「bible-buddy-web 需要 uv 套件管理器。請參考 https://docs.astral.sh/uv/getting-started/installation/ 安裝後再試。」
The bible-buddy skill must be installed alongside it
{WEB}/.claude/skills/bible-buddy
is a symlink to the sibling skill, and the server imports its
scripts/
(FHL fetcher, book names, Desktop detection) and reads its
references/
tables. Verify before launching:
bash
test -d {WEB}/.claude/skills/bible-buddy/scripts && echo OK
Not OK → tell the user to install bible-buddy the same way (
npx skills add lancetw/skills -g -s bible-buddy
).
必須安裝
uv
(執行
which uv
確認)。若未安裝,請告知使用者: 「bible-buddy-web 需要 uv 套件管理器。請參考 https://docs.astral.sh/uv/getting-started/installation/ 安裝後再試。」
必須同時安裝bible-buddy技能
{WEB}/.claude/skills/bible-buddy
是指向同級技能的符號連結,伺服器會匯入其
scripts/
(FHL擷取器、書卷名稱、桌面偵測)並讀取其
references/
表格。啟動前請驗證:
bash
test -d {WEB}/.claude/skills/bible-buddy/scripts && echo OK
若驗證不通過 → 告知使用者以相同方式安裝bible-buddy(
npx skills add lancetw/skills -g -s bible-buddy
)。

Launch

啟動

bash
uv sync --directory {WEB}
uv run --directory {WEB} uvicorn server:app --port 8765
The user named a passage (
/bible-buddy-web 路加福音
)? Two cases, and neither is "launch and let them type it in":
  • Server not running yet → put it in the launch environment. The page then opens straight on that passage; without this it opens on whatever the browser last read and flips a second later.
    bash
    BIBLE_BUDDY_PASSAGE='路加福音' uv run --directory {WEB} uvicorn server:app --port 8765
    BIBLE_BUDDY_VERSION
    sets the translation (default
    rcuv
    ).
  • Server already running →
    POST /api/display
    , below.
Run it in the background and leave it running — the page is the deliverable, and the agent turns it serves take minutes. The server opens the page in the default browser once it is ready; still give the user the URL (
http://127.0.0.1:8765
) in case the browser is not where they are looking.
BIBLE_BUDDY_NO_OPEN=1
suppresses the auto-open.
Port 8765 taken → pick another, pass it as
--port
(the auto-open reads that flag) and say which one you used. The server binds loopback only.
bash
uv sync --directory {WEB}
uv run --directory {WEB} uvicorn server:app --port 8765
使用者指定了經文
/bible-buddy-web 路加福音
)?分兩種情況,皆非「啟動後讓使用者自行輸入」:
  • 伺服器尚未執行 → 將經文加入啟動環境。頁面隨後會直接開啟該經文;若未設定,頁面會開啟瀏覽器上次閱讀的內容,並在一秒後切換。
    bash
    BIBLE_BUDDY_PASSAGE='路加福音' uv run --directory {WEB} uvicorn server:app --port 8765
    BIBLE_BUDDY_VERSION
    用於設定譯本(預設為
    rcuv
    )。
  • 伺服器已在執行 → 使用下方的
    POST /api/display
請在背景執行並保持執行狀態 — 頁面是交付成果,agent處理請求需數分鐘。伺服器準備就緒後會在預設瀏覽器中開啟頁面;仍需提供使用者URL(
http://127.0.0.1:8765
),以防瀏覽器不在使用者預期位置。設定
BIBLE_BUDDY_NO_OPEN=1
可關閉自動開啟功能。
若連接埠8765已被占用 → 選擇其他連接埠,透過
--port
參數指定(自動開啟功能會讀取此旗標),並告知使用者使用的連接埠。伺服器僅綁定環回位址。

The proxy trap

Proxy陷阱

The server drops loopback
HTTP(S)_PROXY
variables at import, on purpose. A package-manager guard exports a short-lived proxy that dies with it, and the Claude CLI the SDK spawns would inherit it and fail every call with "Connection refused". Leave that block alone.
伺服器會在匯入時刻意移除環回
HTTP(S)_PROXY
變數。套件管理器會匯出一個短期Proxy,隨其結束而終止,而SDK啟動的Claude CLI會繼承此Proxy,導致每次呼叫都失敗並顯示「連線被拒絕」。請勿修改此區塊。

Driving the page from Claude Code

透過Claude Code控制頁面

The page is not only steered from its own input box.
POST /api/display
sets what the browser should be showing; the page polls every 2s and loads it. Use this whenever the user asks for a passage while the app is running — do not tell them to type it in themselves.
bash
curl -s -X POST http://127.0.0.1:8765/api/display \
  -H 'content-type: application/json' \
  -d '{"ref": "約翰福音 3:16", "version": "rcuv"}'
  • ref
    takes the same grammar as the page's own box:
    約翰福音 3:16
    ,
    以賽亞書 7:10-17
    ,
    創世記 1
    (whole chapter),
    約翰福音
    (= chapter 1). It is parsed by the page, so a bad reference shows up on the page's banner, not in this call's response.
  • version
    rcuv
    /
    lcc
    /
    bhs
    /
    nt
    . Omit it to keep the one on screen; omit
    ref
    to change only the version.
  • The response echoes
    rev
    , a counter in server memory.
    GET /api/display
    reads it back. A page opened after the command still obeys it: the page asks
    /api/display
    before it falls back to the passage in its own localStorage, so a pending command wins on first paint.
The command changes the passage, which restarts the agent session and switches the notes file, exactly as if the user had pressed 載入.
頁面不僅可透過自身輸入框操作。
POST /api/display
可用於設定瀏覽器顯示內容;頁面每2秒輪詢一次並載入內容。當使用者在應用執行期間請求經文時,請使用此方法 — 勿告知使用者自行輸入。
bash
curl -s -X POST http://127.0.0.1:8765/api/display \
  -H 'content-type: application/json' \
  -d '{"ref": "約翰福音 3:16", "version": "rcuv"}'
  • ref
    支援與頁面輸入框相同的語法:
    約翰福音 3:16
    以賽亞書 7:10-17
    創世記 1
    (整章)、
    約翰福音
    (=第1章)。由頁面負責解析,無效參考會顯示在頁面標題列,不會出現在此呼叫的回應中。
  • version
    — 支援
    rcuv
    /
    lcc
    /
    bhs
    /
    nt
    。省略則保留當前顯示的譯本;省略
    ref
    則僅變更譯本。
  • 回應會回傳
    rev
    ,即伺服器記憶體中的計數器。
    GET /api/display
    可讀取此計數器。在執行此命令後開啟的頁面仍會遵循該命令:頁面會先請求
    /api/display
    ,再回退到自身localStorage中的經文,因此待處理命令會優先顯示。
此命令會更換經文,重啟agent工作階段並切換筆記檔案,效果與使用者點擊「載入」完全相同。

What the page does

頁面功能說明

Passage bar — reference plus version (和合本修訂版 / 呂振中 / BHS 希伯來文 / NT 希臘文), fetched from FHL.
以賽亞書 7
(no verses) loads the whole chapter. Translator footnotes are split out of the verse text into a 譯註 list, and note anchors are offsets into the stripped text.
🔍 全本搜尋 — keyword search across all 66 books (FHL
se.php
), in whichever version the bar has selected. A hit loads that whole chapter and scrolls to the verse. The search index carries some versions in their Strong's-number edition, so hit previews are stripped before display; an original-language version finds nothing for a Chinese keyword.
原文 — two views, both off by default:
  • 「原」 in the verse gutter expands FHL's word analysis (
    qp.php
    , one verse per call — a whole chapter errors out) under that verse: the original verse, every word with its 字形分析 and 中文字義, and a 直譯 line. Hebrew renders RTL, Greek LTR. Clicking a word opens its Strong's entry (
    sd.php
    ) in the note card — transliteration, 欽定本 counts, gloss tree. Plain text, escaped, never run through the markdown renderer.
  • ⇄ 雙欄對照 puts a second version in a right-hand column, verse-aligned.
    原文
    picks BHS or NT 希臘文 by testament. It reads through
    /api/side
    , which deliberately does not touch the server's passage state or restart the agent session the way
    /api/passage
    does.
Both survive
render()
(which rebuilds
#verses
on every note change) because the open verses and their fetched data live in module state, not in the DOM.
Notes land on the words. Four sources, each tagged on its card:
AuthorWhere it comes fromCost
refs
bible-buddy's own
translation-bias.md
/
commonly-misread-passages.md
tables, matched to the loaded verses, served in Chinese through
references/zh-notes.json
free, instant, already verified
quick
✨ 生成 ELI5 筆記 — one schema-constrained model pass, 10–14 notes for the whole passageone paid pass, cached per passage+version
agent
the chat agent calling
mcp__notes__add_annotation
during a turn
part of the turn
user
反白經文 → ✎ 手動筆記free
反白 a phrase → ✨ ELI5 筆記 writes one note for exactly those words (not cached — the user asked for that one). A
quick
note is flagged 未驗證; its card offers 🔍 請 agent 驗證, which sends the agent a turn that ends in
mcp__notes__update_annotation
on the same id, so the note is rewritten in place rather than duplicated.
Chat streams over SSE. A refreshed page reattaches to the running turn instead of losing it. Changing passage starts a fresh agent session, since the old history is about other verses.
經文列 — 包含參考書卷與譯本(和合本修訂版 / 呂振中 / BHS 希伯來文 / NT 希臘文),從FHL擷取。
以賽亞書 7
(未指定節數)會載入整章。譯者註腳會從經文中拆分出來,形成「譯註」清單,註解錨點對應於去除格式後的文字偏移量。
🔍 全本搜尋 — 在所有66卷書中進行關鍵字搜尋(使用FHL
se.php
),搜尋範圍為經文列中選擇的譯本。搜尋結果會載入對應整章並捲動到對應節數。部分譯本的搜尋索引包含Strong編號版本,因此搜尋結果預覽會先去除格式後顯示;原文版本無法搜尋到中文關鍵字。
原文 — 兩種檢視模式,預設皆關閉:
  • 節數旁的「原」按鈕會展開該節的FHL詞彙分析(
    qp.php
    ,一次呼叫一節 — 呼叫整章會出錯):原文經文、每個單字的「字形分析」與「中文字義」,以及「直譯」行。希伯來文從右到左顯示,希臘文從左到右顯示。點擊單字會在註解卡片中開啟其Strong編號條目(
    sd.php
    ) — 包含 transliteration、欽定本出現次數、釋義樹狀結構。純文字格式,已跳脫特殊字元,不會經過markdown渲染器處理。
  • ⇄ 雙欄對照會在右欄顯示另一個譯本,節數對齊。「原文」會根據舊約/新約選擇BHS或NT希臘文。透過
    /api/side
    讀取,刻意不會
    /api/passage
    那樣變更伺服器的經文狀態或重啟agent工作階段。
兩種模式皆可在
render()
(每次註解變更時重建
#verses
)後保留,因為展開的節數與其擷取的資料儲存於模組狀態,而非DOM中。
註解依附於字詞。來源分為四種,每種都會在卡片上標註:
來源出處成本
refs
bible-buddy自身的
translation-bias.md
/
commonly-misread-passages.md
表格,與載入的節數匹配,透過
references/zh-notes.json
提供中文版本
免費、即時、已驗證
quick
✨ 生成ELI5筆記 — 一次符合schema約束的模型呼叫,整段經文生成10–14個註解一次付費呼叫,按經文+譯本快取
agent
聊天agent在交談回合中呼叫
mcp__notes__add_annotation
生成
包含在交談回合成本中
user
反白經文 → ✎ 手動筆記免費
反白片語 → ✨ ELI5筆記會針對該片段生成一個註解(不進行快取 — 使用者主動請求)。
quick
註解會標註「未驗證」;其卡片提供「🔍 請agent驗證」選項,會傳送一個交談回合,最終呼叫
mcp__notes__update_annotation
更新同一id的註解,因此註解會就地重寫而非重複新增。
聊天透過SSE串流傳輸。重新整理頁面會重新連接到正在進行的交談回合,不會遺失對話記錄。更換經文會啟動新的agent工作階段,因為舊對話歷史與其他節數相關。

The reference tables are English

參考表格為英文

bible-buddy's tables are written in English, and this is a Chinese reading desk.
references/zh-notes.json
holds the Traditional Chinese
label
and
body
of every row, keyed by the note id that
_ref_notes()
derives from the row's own cells. A row with no entry serves in English rather than failing, and a passage whose notes were saved before the file existed is re-translated when it is loaded again.
Upstream edits a row → its cells change → its id changes → it falls back to English until regenerated:
bash
uv run --directory {WEB} python translate_refs.py        # only the ids the file is missing
uv run --directory {WEB} python translate_refs.py --force  # all 96 rows again
That is a paid model pass (about US$2 for the whole set, ~$0.10 per batch of 6). Don't run it as a side effect of something else; the committed JSON is what makes these notes free at read time.
bible-buddy的表格以英文撰寫,而此工具為中文閱讀平台。
references/zh-notes.json
儲存了每一行的繁體中文
label
body
,以
_ref_notes()
從行內儲存格衍生的註解id作為鍵值。若某行無對應條目,則會顯示英文而非失敗;若某段經文的筆記在該檔案建立前已儲存,則會在重新載入時重新翻譯。
上游編輯某行 → 儲存格內容變更 → id變更 → 會回退顯示英文,直到重新生成:
bash
uv run --directory {WEB} python translate_refs.py        # 僅翻譯檔案中缺少的id
uv run --directory {WEB} python translate_refs.py --force  # 重新翻譯全部96行
此操作需要付費模型呼叫(整組約2美元,每6行批次約0.10美元)。請勿做為其他操作的副作用執行;已提交的JSON是確保這些註解在閱讀時免費的關鍵。

Where the work is saved

儲存位置

~/Desktop/bible-buddy/notes/<reference> (<version>).json
, rewritten atomically on every mutation, plus
.last-passage.json
so a restarted server restores what the page is showing. Deleted notes are remembered as hidden ids — the cached ELI5 pass must not resurrect them.
~/Desktop/bible-buddy/notes/<reference> (<version>).json
,每次變更時會原子化重新寫入,另外還有
.last-passage.json
,以便重新啟動的伺服器還原頁面顯示的內容。已刪除的註解會以隱藏id的形式保留 — 快取的ELI5呼叫不得重新生成這些註解。

When something goes wrong

問題排除

✗ ELI5 筆記失敗:API 529 過載 — the pass is not cached on failure, so the button doubles as retry. Retries are capped at 3 and the pass has a 180s ceiling, by design: the CLI's own ~10 retries kept the spinner up for minutes.
「尚未載入經文」 — chat, ELI5 and notes all need a passage; the server reloads the last one automatically, so this means that reload also failed (usually FHL unreachable).
A quote that does not match the verse — the note degrades to verse-level (no underline) instead of failing. Expected, not a bug.
Failures surface rather than being swallowed. Read the uvicorn stderr for
model pass:
/
model retry:
/
quick pass failed:
lines before theorising.
✗ ELI5筆記失敗:API 529過載 — 失敗時不會快取呼叫,因此按鈕兼具重試功能。重試次數上限為3次,呼叫時長上限為180秒,此為設計考量:CLI本身的約10次重試會讓載入動畫持續數分鐘。
「尚未載入經文」 — 聊天、ELI5與註解都需要經文;伺服器會自動重新載入上次的經文,因此此訊息表示重新載入也失敗(通常是FHL無法連線)。
引用內容與經文不符 — 註解會降級為節級顯示(無底線)而非失敗。此為預期行為,並非bug。
錯誤會直接顯示而非隱藏。請先閱讀uvicorn標準錯誤輸出中的
model pass:
/
model retry:
/
quick pass failed:
行,再進行問題推斷。