Skip to main content

PyPI - Version PyPI - Python Version PyPI - Downloads codecov

booktx

booktx is a deterministic local CLI that prepares Markdown and EPUB documents for translation by a coding agent or human translator.

It:

  • extracts source text into stable record chunks,
  • tracks progress and translation versions,
  • hands out safe translation tasks,
  • validates submissions,
  • rebuilds translated output.

booktx never translates text itself and makes no network calls.

Install

pip install -e .

For development and docs:

python -m pip install -e ".[dev,docs]"

Python 3.10+ is supported.

Core model

Profile = hard boundary for mutable translation state
Access mode = determines whether sibling profiles are visible
Version = history/candidate boundary inside that profile

.booktx/ now holds only shared source-derived state. Mutable translation state lives under translations/<profile>/.

Project layout

book/
  source/
    book.epub

  .booktx/
    source-config.toml
    source-manifest.json
    names.json
    chapter-map.json
    chunks/

  translations/
    PROFILE/
      .booktx-profile.json
      config.toml
      identity.json
      context.json
      context.md
      translation-store.json
      translation-version-ledger.json
      tasks/
      ingest/
      translated/
      reports/
      output/
        book.de.epub

Quickstart

booktx init ./demo --source-file book.epub --source-lang en
booktx extract ./demo

booktx profile create ./demo PROFILE \
  --target de \
  --target-locale de-DE \
  --model codex-openai/gpt-5.5@low \


booktx context init ./demo --profile PROFILE --non-interactive
booktx context questions ./demo --profile PROFILE
# Ask the user to approve or edit answers before continuing.
booktx context approve ./demo --profile PROFILE Q001 --text "<USER_APPROVED_TEXT>" --approved-by "user:<USER>"
booktx context render ./demo --profile PROFILE --write
booktx context mark-ready ./demo --profile PROFILE

booktx translate next ./demo \
  --profile PROFILE \
  --unit batch \
  --max-words 800 \
  --format block

booktx translate insert ./demo \
  --profile PROFILE \
  --task-id TASK \
  --file translations/PROFILE/ingest/TASK.block.txt \
  --format block

booktx validate ./demo --profile PROFILE
booktx build ./demo --profile PROFILE

Collaborative vs isolated profile-root mode

booktx supports two deliberate access modes:

  1. Collaborative project-root mode: start the harness at the book project root when you need profile administration, profile comparison, or other cross-profile work.
  2. Isolated profile-root mode: start the harness inside translations/<profile>/ when you want unbiased model evaluation without normal booktx workflows revealing sibling profiles.

Profile-root isolation is booktx-mediated isolation, not OS sandboxing. It depends on two things:

  • the harness starts inside translations/<profile>/ and blocks parent paths, absolute paths, sibling profile paths, shell globs, and arbitrary filesystem inspection snippets;
  • booktx commands are used with project argument . and do not print parent or sibling paths.

If a profile-root command suggests ../, prints an absolute path, or reveals a sibling profile, stop and report a booktx isolation bug.

Isolated evaluation workflow

From book/translations/PROFILE/:

booktx mode .
booktx doctor isolation .
booktx source status .
booktx context status .
booktx translate next . --unit batch --max-words 800 --format block
booktx translate insert . --task-id TASK --file ingest/TASK.block.txt --format block
booktx validate .
booktx build .

In this mode, booktx automatically binds the current profile, brokers source access internally, and renders profile-local paths such as tasks/..., ingest/..., reports/..., and output/....

Generated AGENTS.md files

Before starting an agent harness, write the matching harness instructions:

booktx agents write . --mode isolated --profile PROFILE
cd translations/PROFILE

For project-root collaboration:

booktx agents write . --mode collaborative

booktx deletes only AGENTS.md files it generated itself. User-authored files are never silently overwritten or removed. Use booktx agents status . to inspect ownership and booktx agents clean . --mode all to remove generated files.

Source-analysis review queue

Use source analysis to mine translation-risk terms before real translation starts:

booktx source analyze ./demo --write
booktx source analyze ./demo --write --sync-profiles
booktx source analysis ./demo/translations/PROFILE

This is a review queue, not an approval step. The canonical JSON is authoritative and the Markdown is a readable bucketed queue for binding glossary candidates, names/titles, rare terms, and suppressed noise.

To turn reviewed candidates into context state:

booktx context prefill ./demo --profile PROFILE --from-source-analysis
booktx context prefill ./demo --profile PROFILE --from-source-analysis --include-advisory --write
booktx context promote-candidate ./demo CAND-... --profile PROFILE --as-question --write
booktx context promote-candidate ./demo CAND-... --profile PROFILE --target "Imperium" --require-target --enforce error --write
booktx source ignore-candidate ./demo CAND-... --reason "ordinary vocabulary" --write

Default context prefill --from-source-analysis creates review questions for binding/name/rare candidates and does not open advisory glossary entries by default. If a profile-root source analysis read reports a missing snapshot, rerun project-root analysis with --write --sync-profiles.

Bounded agent runs

When asking an agent to continue for several chapters, create a durable todo:

booktx translate todo-next ./demo \
  --profile PROFILE \
  --chapters 3 \
  --batch-words 800 \
  --max-run-words 12000 \
  --write

This writes a todo file (not translations) under translations/<profile>/todos/. Continue bounded runs with:

booktx translate todo-status ./demo --profile PROFILE --latest
booktx translate todo-resume ./demo --profile PROFILE --latest --format block
booktx check ./demo --profile PROFILE --fail-on-warnings

Single large chapters

If the user asks to finish a single chapter that has more than the safe task budget (default 800 source words), booktx automatically creates or reuses a single-chapter todo and returns bounded batch tasks:

booktx translate next ./demo --chapter 0005 --unit chapter --max-words 800

This creates a todo for chapter 0005 and returns the first bounded batch. Continue with booktx translate todo-resume until the chapter completes.

To override this behavior and force a whole-chapter task:

booktx translate next ./demo --chapter 0005 --unit chapter --force-chapter

After each chapter, run booktx check before adding the chapter note:

booktx check ./demo --profile PROFILE --chapter 0005 --fail-on-warnings
booktx context chapter-note ./demo --profile PROFILE 0005 ...

--max-run-words is advisory only: it tells the agent when to stop and report progress, but booktx does not hard-stop accepted work at that threshold. Prefer batches over chapter-sized tasks. not create a new dotted translation version. Dotted versions track baseline policy changes such as style, glossary, answered questions, global rules, readiness, source metadata, language metadata, or actor/model track changes.

Final release output

For final release output, prefer:

booktx validate ./demo --profile PROFILE --fail-on-warnings
booktx build ./demo --profile PROFILE --require-complete

Translated EPUB builds write the resolved target language to publication and content-document metadata and inject one deterministic best-effort hyphenation style sheet. This is a metadata/author-style correctness contract; actual hyphenation still depends on the reading system. If a reader produces bad breaks, set hyphenation = "none" under [epub_output] in the profile config and rebuild. Pass-through output stays byte-identical by default. See EPUB output-language and hyphenation policy.

Editor QA indexes

Refresh editor-friendly indexes:

booktx translate export-index ./demo --profile PROFILE

This writes:

  • translations/PROFILE/source-index.json -- source text only, best for reading/searching the original source inside the profile, including isolated profile runs.
  • translations/PROFILE/target-index.json -- target text only, best for searching translated terms without English source false positives.
  • translations/PROFILE/source-target-index.json -- slim source/target side-by-side view, best for scanning translation fit in an editor.
# Search only the original source language.
rg "Wasp" translations/PROFILE/source-index.json

# Search only translated German target text.
rg "Wespen" translations/PROFILE/target-index.json

# Scan source and target side by side.
nvim translations/PROFILE/source-target-index.json

# Inspect canonical state for a hit.
booktx translation get-record ./demo 0014-000029 --profile PROFILE --json

All three files are generated artifacts. Do not edit them manually. The canonical state remains translation-store.json.

Pass-through validation profile

Use a pass-through profile to verify that extraction and EPUB reconstruction include all text before doing real translation:

booktx extract ./demo
booktx pass-through ./demo --profile passthrough_en --create

This writes source-as-target translated chunks under translations/passthrough_en/translated/, validates complete coverage, and builds translations/passthrough_en/output/.... Compare the output EPUB against source/book.epub with an EPUB diff viewer. The included EPUB fixture should be byte-identical, but real-world EPUBs should be treated as reconstruction checks, not guaranteed byte-for-byte copies. Never run pass-through against a real translation profile.

Multiple profiles

Create one profile per target language, model experiment, or hard-isolated context experiment. Two profiles can target the same language with different models, or the same model with different languages:

booktx profile create ./demo PROFILE --target de --model codex-openai/gpt-5.5@low
booktx profile create ./demo PROFILE_B --target de --model glm-5.2
booktx profile create ./demo fr_gpt5_5 --target fr --model codex-openai/gpt-5.5@low

Profile resolution

When a command needs a single profile, booktx resolves it in this order:

Project-root profile commands require --profile PROFILE;
otherwise fail for target-state commands.

If a project has more than one profile, always pass --profile.

Live identity

profile list and profile show render the current identity from translations/<profile>/identity.json, which is updated by booktx model set, actor set, and harness set. The identity embedded in config.toml is only the initial default captured at creation.

Legacy projects

Old single-layout projects can be migrated in place:

booktx profile migrate-current ./demo PROFILE

CLI identity overrides (--model, --actor, --harness) are honored over any legacy .booktx/identity.json.

Common commands

booktx status ./demo
booktx status ./demo --profile PROFILE
booktx mode ./demo
booktx profile list ./demo
booktx profile show ./demo PROFILE
booktx whoami ./demo --profile PROFILE
booktx version current ./demo --profile PROFILE
booktx translate task-status ./demo --profile PROFILE --task-id TASK
booktx translation compare ./demo --profile PROFILE 74@38 --versions 1.1,1.2
booktx profile compare ./demo --profiles PROFILE,PROFILE_B --record 0001-000001
booktx source status ./demo

# Series-wide context packs (style/global rules/glossary/approved answers):
booktx context export-pack ./book1 --profile PROFILE \
  --series-id shadows-of-apt --output ./soa.en-de.booktx-context-pack.json
booktx context import-pack ./book2 --profile PROFILE \
  --file ./soa.en-de.booktx-context-pack.json --write

# Prepare the next book in a series:
booktx series prepare ./book5 \
  --source-file ./book5/book5.epub \
  --from-book ./book4 \
  --from-profile PROFILE \
  --profile PROFILE \
  --series-id shadows-of-apt \
  --title "Shadows of the Apt / German policy" \
  --target de \
  --target-locale de-DE \
  --model zai/glm-5.2@high \
  --write
booktx series recipe write ./book5 --profile PROFILE --series-id shadows-of-apt --title "Shadows of the Apt / German policy" --output ../soa.de.booktx-series.toml

# Same-book sibling profile policy sync:
booktx context sync ./demo \
  --from PROFILE \
  --all-compatible \
  --section glossary \
  --term "Empire"

# Build a judge/selection profile from sibling outputs:
booktx judge create-profile ./demo JUDGE_PROFILE \
  --target de \
  --target-locale de-DE \
  --sources PROFILE,PROFILE_B \
  --context-from PROFILE \
  --model gpt-5.5 \

booktx judge status ./demo --profile JUDGE_PROFILE
booktx judge accept-identical ./demo --profile JUDGE_PROFILE --sources PROFILE,PROFILE_B --unit chapter --chapter 0001 --max-records 100 --write
booktx judge next ./demo --profile JUDGE_PROFILE --sources PROFILE,PROFILE_B --unit chapter --chapter 0001 --max-records 8 --format decisions

For isolated judge work, prepare the snapshot from the project root then cd into the profile root:

booktx judge prepare-isolation ./demo --profile JUDGE_PROFILE --write
cd translations/JUDGE_PROFILE
booktx judge status .
booktx judge accept-identical . --unit chapter --chapter 0001 --max-records 100 --write
booktx judge next . --unit chapter --chapter 0001 --max-records 8 --format decisions
booktx judge insert . --judge-task-id TASK --file judge-ingest/TASK.decisions.txt --format decisions
booktx judge reset-ingest . --judge-task-id TASK --format decisions --write
booktx judge continue . --max-records 8

For decision_kind: copy, leave TARGET empty and let booktx copy the selected candidate exactly. Use decision_kind: edited only when the final target differs from every candidate. Judge record ids are chunk-based, so a task for chapter 0005 can still contain records whose ids start with 0001-.

When one source is clearly best, create a single-source revision profile with --purpose revise. Every record then requires an explicit copy or edited judge decision; accept-identical, sweep-identical, and prefill-policy-fixes are disabled, and effective output stays valid only while each active target has matching judge-decision provenance. Use booktx judge record . --record RECORD_ID for later corrections. See docs/profiles.md for the full workflow.

booktx translate next also snapshots the exact effective task context under translations/<profile>/context-history/views/<sha>/. New tasks carry both the baseline version (for example 1.2) and the immutable context-view evidence used for that task, and accepted candidates preserve that evidence.

Translation contract

  • record ids must stay unchanged;
  • placeholders must stay unchanged;
  • targets must be non-empty;
  • submissions must stay in the selected profile;
  • translations/<profile>/translation-store.json is the primary record-level state;
  • translations/<profile>/translated/*.json is compatibility/export output.

Documentation

Context approval

booktx never decides translation policy by itself. An agent may propose context answers, but the user must approve them before translation begins. Do not use context mark-ready --force during normal translation work.

EPUB inline XHTML records

EPUB records may expose constrained inline XHTML fragments such as <em>, <strong>, <span class="...">, <a href="...">, <sup>, <sub>, or <code>. Translators must preserve tags and attributes around the equivalent target-language phrase and must not replace XHTML with Markdown markers.

Quality review commands

Quality review is an optional workflow that improves already-accepted translations:

  • booktx review status . -- report review coverage
  • booktx review next . --pass 1 -- create a review task for pass 1
  • booktx review insert . --review-task-id TASK --file reviews/TASK.block.txt -- accept review results
  • booktx review activate . RECORD R1.2 -- manually activate a review candidate

Review candidates are stored separately from translation versions in translations/<profile>/reviews/. The effective output resolves as active_review (if valid) -> active_version -> missing.

Enable quality review by adding [quality_review] to the profile's config.toml. See docs/profiles.md for configuration reference.

Glossary correction

# Fix wrong forbidden targets (replaces, doesn't append).
booktx context add-term . "empire" --target "Imperium" --forbid "Reich" --forbid "Empire"

# Remove a wrong entry.
booktx context remove-term . "empire"

Mandatory glossary decisions

For user terminology decisions (e.g. \u201calways translate tenday as Dekade\u201d), use mandate-term. It sets require_target = true and defaults to enforce = error so the approved target is positively enforced. It never accepts --enforce off:

booktx context mandate-term . "tenday" \
  --source-variant "tendays" \
  --target "Dekade" --target-variant "Dekaden" \
  --forbid "Zehntag" --forbid "Zehntage" --forbid "zehn Tage" \
  --category "calendar"

Longer mandatory phrases shadow contained shorter source terms. For example:

booktx context mandate-term . "Mole Cricket-kinden" \
  --target "Maulwurfsgrillenart" --category "kinden"

This permits the natural compound without requiring the shorter Cricket-kinden -> Grillenart target token for that contained occurrence. Standalone shorter occurrences remain enforced. Any mandatory glossary change requires a fresh translation task, including batch and todo-created tasks.

reset-term and add-term also accept --source-variant, --target-variant, and --require-target. Use --allow-disable-enforcement to intentionally set --enforce off on a mandatory rule. Advisory approved-target-only entries may use enforce = off without warning.

Auditing a term

After a mandatory glossary change, audit the effective output for one term:

booktx context audit-term . "tenday" --profile de_deepseekv4_flash

Generate a safe correction-block template for violating records:

booktx context audit-term . "tenday" \
  --write-block ingest/glossary-tenday-fixes.block.txt
booktx translation revise-block . \
  --file ingest/glossary-tenday-fixes.block.txt --format block --activate
booktx validate . --fail-on-warnings

The ingest block contains only record headers and editable current targets. A companion reference-only source block is written alongside it. Only violating effective records are included; the generator never guesses the corrected translation.

Active-only validation

booktx validate checks only the effective output by default. Historical inactive versions that contain forbidden terms no longer cause warnings. Use --include-inactive for history audits:

booktx validate . --include-inactive --fail-on-history-warnings

Deterministic terminology correction

Use booktx translation search for terminology fixes instead of inspecting stores directly. Combine source and target criteria with --match all, add regex/exclusion filters when needed, and write profile-local correction blocks with --write-block. Glossary rendering distinguishes binding rules from advisory and disabled entries; enforce alone is not binding without require_target or forbidden targets. Revision commands preserve baseline and chapter-scoped context-view metadata.

Translation preference dictionary / termbase

Use the termbase for reusable cross-book lexical preferences and literalism traps that should appear only when their source cue matches the current records. Keep fixed terminology, names, and mandatory target enforcement in the glossary; keep softer word-sense and collocation guidance in termbase shards.

Store the termbase as one JSON shard per target language/locale:

~/.config/booktx/translation-termbase/de.json
.booktx/termbase/de.json
translations/<profile>/termbase-overrides/de-DE.json

Read-only commands can run from project root or isolated profile roots:

booktx termbase status . --json
booktx termbase scan-source . --jsonl
booktx termbase audit . --jsonl
booktx termbase write-review . --pass 1

Global-only workflows also work outside a project:

booktx termbase add \
  --scope global \
  --language de \
  --id LEX-MOULDY \
  --source "mouldy principles" \
  --source-regex "\\bmouldy\\s+principles(?:\\s+of\\s+magic)?\\b" \
  --preferred "schäbige Prinzipien" \
  --forbid "schimmligen Prinzipien" \
  --approve

booktx termbase export --scope global --language de --output ./termbase-de.json
booktx termbase import --scope global --language de --input ./termbase-de.json --mode merge

Isolated profile-root mode may read the global termbase and write profile overlays, but it must not mutate global or project shards. Paths stay redacted (~ or $BOOKTX_TERMBASE_DIR/...) instead of leaking absolute locations.

When the user reports a bad context-sensitive translation:

  1. Fix the current effective output with translation revise-record or review revise-record, depending on whether the effective target is a translation or an active review.
  2. Add a local glossary entry only when the phrase is fixed and safely enforceable.
  3. Add or promote a reusable termbase entry for the broader sense preference.
  4. Run booktx termbase audit . --jsonl and booktx qa-scan . --forbidden --glossary --include-advisory --jsonl.
  5. Use booktx termbase write-review . --pass 1 when the termbase finding should create normal review work instead of an immediate deterministic rewrite.

Starting the next book in a series

Prefer the orchestration command:

booktx series prepare ./book5 \
  --source-file ./book5/book5.epub \
  --from-book ./book4 \
  --from-profile de_glm_5_2 \
  --profile de_glm_5_2 \
  --series-id shadows-of-the-apt \
  --title "Shadows of the Apt German series context" \
  --target de \
  --target-locale de-DE \
  --model zai/glm-5.2@high \
  --write \
  --write-termbase \
  --termbase-scope project

booktx series prepare stops before translation and before automatic context mark-ready. Review the generated context/questionnaire, approve any new source-analysis questions, then run booktx context mark-ready followed by booktx agents write ... --mode isolated.

The manual context export-pack / init / extract / profile create / context import-pack / source analyze / context prefill sequence still works unchanged when you need full control.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

booktx-0.4.1.tar.gz (649.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

booktx-0.4.1-py3-none-any.whl (454.2 kB view details)

Uploaded Python 3

File details

Details for the file booktx-0.4.1.tar.gz.

File metadata

  • Download URL: booktx-0.4.1.tar.gz
  • Upload date:
  • Size: 649.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for booktx-0.4.1.tar.gz
Algorithm Hash digest
SHA256 523a84623e668d22b3145913dacdbd5bf65b341f12730aed93b80979fdcddbc2
MD5 31540a8d23c156f0b5aaf877739d5ec7
BLAKE2b-256 02b096e89e57d1ac432c486f6220a815710a356d40e3c84ec7c9fa3164f60bb4

See more details on using hashes here.

File details

Details for the file booktx-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: booktx-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 454.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for booktx-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5392589360aa8bd12dd974e192df94cc4d5e59d9d4ba49251f96b9fb15b45eea
MD5 005b69ea13391bc744369caa93db8241
BLAKE2b-256 ad94c6472b8450c31055f07d4f7e270a28912fc93f8fd48764317379c001d6b8

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.1

2 files

0.5.0

2 files

0.4.3

2 files

0.4.2

2 files

This release

0.4.1 This release

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page