BookExport is a Paper 26.2 administration plugin that turns a written book or book and quill into a UTF-8 .txt file. Its CMI output profile preserves Minecraft page order, colors, decorations, blank lines, Unicode text, and placeholder-looking tokens while producing valid CMI CustomText pagination.
Fresh installations use a review-first workflow: an author stages a draft, a trusted administrator reviews it, and an administrator publishes it into CMI's CustomText directory. Existing version 2 configurations continue in direct compatibility mode until an administrator deliberately migrates them.
The 2.0.2 release modernizes the original 1.21 plugin with Java 25 bytecode, stable Paper 26.2 APIs, Adventure messages, Gradle, correct CMI pagination, granular permissions, validated workflow directories, collision-safe publication, content-free draft manifests, a durable publication journal with read-only recovery inspection, diagnostics, and regression tests.
Canonical player documentation: docs.1moreblock.com/custom-server-plugins/bookexport/
| Component | Supported target |
|---|---|
| Server | Paper 26.2 only |
| Compile API | io.papermc.paper:paper-api:26.2.build.84-stable |
| Server release | Paper 26.2 STABLE build 84 (Paper-26.2.jar) |
| Java bytecode | Java 25 |
| Tested runtimes | Oracle Java 25.0.4 and 26.0.2 |
| Build tool | Gradle 9.4.1 wrapper |
| BookExport | 2.0.2 (release build 019) |
Older Minecraft, Paper, Spigot, and Java releases are intentionally unsupported.
The README is the complete technical overview. Focused source pages are available for readers and for the namespace-safe central documentation importer:
| Page | Audience and purpose |
|---|---|
| Player guide | Friendly introduction, trusted-author workflow, commands, limits, and important consequences |
| Commands | Complete command, alias, console/player, and click-action reference |
| Permissions | Defaults, inheritance, replacement separation, and legacy aliases |
| Placeholders | Filename and pagination tokens plus PlaceholderAPI behavior |
| Configuration | Every setting, validation rule, persistence behavior, reload, and version 2 migration |
| Installation | Java/Paper requirements, build, clean install, update, and readiness checks |
| Integrations | Exact CMI, CMILib, PlaceholderAPI, LuckPerms, and Vault relationships |
| Troubleshooting | Controlled failure states and recovery guidance |
| Importer manifest | Stable project identity for the central 1MoreBlock documentation system |
Use Minecraft's book editor as an in-game content authoring tool. Hold a finished book and run /bookexport. On a fresh installation, BookExport writes a staged draft for staff review instead of immediately changing a live CMI text. A publisher can inspect the draft outside Minecraft, verify its content-free manifest in-game, record an approval or changes request, and publish it with an explicit command.
With the default CMI profile, the result starts with <AutoPage> and places <NextPage> only between Minecraft pages, so CMI page 1 matches Minecraft page 1.
Typical uses include:
- Drafting and publishing CMI CustomText rules, guides, news, help, and event pages
- Reviewing player-authored server copy before it becomes live
- Archiving published revisions and backing up replaced texts
- Archiving written books as readable UTF-8 text
- Converting Minecraft colors into CMI, MiniMessage, ampersand, section-sign, or plain text
- Supports signed written books and unsigned book-and-quill items in the main hand.
- Uses the signed title automatically or an explicit custom title.
- Provides unambiguous
/bookexport export [title]and/bookexport stage [title]routes for titles that match subcommands. - Stages normal exports by default on config version 3; explicit
stagealways stages, even in direct mode. - Creates an atomic
<draft>.bookexport-manifest.propertiessidecar for each managed staged draft. - Claims a content-free
<draft>.bookexport-creatingmarker before exposing a native staged.txt, so an interrupted pair creation fails closed instead of being mistaken for a legacy draft. - Records stable manifest ID, origin, intended and actual filenames, creator/adopter and book-author metadata, UTC creation/adoption time, page/unit/byte counts, and SHA-256 without storing page content.
- Records exact review and publication states, actors, timestamps, checksums, collision mode, final filename, archive, backup, and outcome.
- Provides review, approval, changes-requested, and paginated history commands while keeping approval recommended and publication backward compatible.
- Publishes reviewed drafts with
fail,unique, or backed-upreplacecollision behavior. - Detects managed drafts changed after staging or approval and blocks unsafe publication until their manifest is reviewed and approved again.
- Attempts an atomic manifest checkpoint immediately after each committed live publication and before archival; a stored pending record blocks repeat publication, and an archival failure retains the draft.
- Plans exact live, archive, and optional backup filenames, then stores a durable content-free transaction before any backup or live mutation.
- Reconciles interrupted transactions by checksum at startup and through read-only recovery list/show commands; it never automatically retries, rolls back, deletes, republishes, finalizes, cleans up, or reloads CMI.
- Preserves page order and page boundaries without reflowing or truncating valid book content.
- Produces correct CMI pagination: controlled
<AutoPage>first line and<NextPage>only between pages. - Preserves CMI and PlaceholderAPI-looking tokens for CMI to resolve for the eventual viewer.
- Converts validated Minecraft colors and decorations to
vanilla,legacy,strip,cmi, orminioutput. - Uses normalized Unicode-aware filenames with configurable templates, lowercasing, length limits, and collision suffixes.
- Writes complete UTF-8 temporary files before collision-safe moves.
- Lists published, staged, archived, or backup files with chat-safe pagination and clickable controls for players.
- Shows staged review status and safe Review, Approve, Changes, and Publish suggestions without executing a mutating action immediately.
- Validates all workflow paths and configuration during startup and reload.
- Offers player-safe
infoandhelp, plus trustedadminanddebugdiagnostics. - Retains the old
exportbook.*permission nodes as compatibility aliases. - Treats compiler warnings as errors and includes unit tests for high-risk conversion and storage logic.
Paper is the only production/plugin API dependency. JUnit and the Paper-aligned Adventure API are used only by the test suite and are not bundled. BookExport does not call the APIs of CMI, CMILib, PlaceholderAPI, Vault, or LuckPerms.
The current test-server versions, reverified on 2026-07-28, are:
| Plugin | Tested version | Relationship to BookExport |
|---|---|---|
| CMI | 9.8.8.5 | Optional consumer of published CustomText files |
| CMILib | 1.5.9.9 | CMI's dependency, not BookExport's dependency |
| PlaceholderAPI | 2.12.3 | Optional; CMI can resolve preserved tokens at display time |
| LuckPerms | 5.5.59 | Optional Bukkit permission provider |
| Vault CMI build | Manifest version 1.7.3-CMI | Unrelated to BookExport |
Do not add these plugins to BookExport's Gradle dependencies unless BookExport later begins calling their APIs.
-
Build the plugin:
./gradlew clean build -
Copy
build/libs/1MB-BookExport-v2.0.2-019-j25-26.2.jarto the Paper 26.2 server'splugins/directory. -
Remove any older BookExport JAR so Paper does not discover two copies.
-
Restart Paper cleanly. Do not use Bukkit
/reloador a hot-reload plugin. -
Confirm
/version BookExportreports2.0.2. -
Confirm
/bookexport infoor/bookexport versionreports build019, the exact stable API, and opens the canonical player documentation. -
Run
/bookexport admin statusand verify config version 3, workflowstaged, five writable workflow/transaction directories, collision modefail, and a clear recovery journal.
If the server already has a version 2 config.yml, BookExport intentionally starts in direct compatibility mode. It does not rewrite the config or move existing files. Follow Migrating a version 2 configuration when ready to enable staged-by-default exports.
-
Give a trusted staff player the non-replacing master node:
/lp user <player> permission set bookexport.admin true -
Put a written book or book and quill in the player's main hand.
-
Preview the rendered output without writing a file:
/bookexport debug preview Server Rules -
Stage the book. With the packaged version 3 config,
/bookexportand/bookexport exportalso stage:/bookexport stage Server Rules -
List the generated draft, then inspect its manifest and verify its current SHA-256:
/bookexport list staged /bookexport admin review server_rules.txt -
After reviewing the
.txtcontent, record approval of its current bytes:/bookexport admin approve server_rules.txtApproval is recommended but deliberately non-blocking for an unchanged unreviewed or older untracked draft. If a managed draft changes, is marked changes-requested, or has a corrupt manifest, BookExport blocks publication until it is reviewed and approved or repaired.
-
Click the draft's Publish action. It fills in a command but does not run it. Review the command and press Enter, or type it directly:
/bookexport admin publish server_rules.txt fail -
Reload CMI and open the published text:
/cmi reload /cmi ctext server_rules <player>
BookExport never runs /cmi reload automatically.
An unchanged unreviewed or legacy draft remains publishable for compatibility. That publication records the publisher as the implicit approving actor, including the exact published SHA-256. Explicit approval is still the recommended staff workflow because it makes the review boundary and reviewed bytes visible before publication.
The bookexport.admin master node does not include bookexport.admin.replace. Grant the latter separately only to administrators who may replace a live text after BookExport creates a backup.
Only grant export access to trusted authors. Book content is intentionally preserved, so CMI directives, interactive tags, and PlaceholderAPI tokens written into a book may become active when CMI displays the published file.
| Command | Description | Permission |
|---|---|---|
/bexport ... |
Alias for any /bookexport ... route |
Same as the routed command |
/bookexport |
Process a signed written book using its title; stages in staged mode and publishes directly in direct mode | bookexport.export |
/bookexport export [title] |
Explicit normal-workflow export; title is required for book and quill | bookexport.export; a custom title also needs bookexport.export.custom-title |
/bookexport stage [title] |
Always create a staged draft, regardless of workflow mode | bookexport.export; a custom title also needs bookexport.export.custom-title |
/bookexport <title> |
Legacy shorthand for a custom-title normal-workflow export | bookexport.export and bookexport.export.custom-title |
/bookexport info |
Introduce BookExport, show installed version/build and compatibility, suggest starting commands, and open the canonical docs or source | bookexport.info |
/bookexport version |
Exact alias for /bookexport info; it never becomes a legacy export title |
bookexport.info |
/bookexport help or /bookexport ? |
Show only commands the sender may use | bookexport.help |
/bookexport status |
Exact shortcut for the generated-metadata-backed admin status | bookexport.admin.status |
/bookexport admin [status] |
Show validated workflow settings and directory health | bookexport.admin.status |
/bookexport admin list [page] |
List published .txt files; published is the backward-compatible default scope |
bookexport.admin.list |
/bookexport admin list <published|staged|archive|backups> [page] |
List files in an explicit workflow scope | Matching bookexport.admin.list... permission |
/bookexport admin review <staged-file> |
Show the draft manifest, review state, and current integrity without displaying content | bookexport.admin.review |
/bookexport admin approve <staged-file> |
Approve the draft's current SHA-256; later changes invalidate that approval | bookexport.admin.approve |
/bookexport admin changes <staged-file> |
Mark a managed draft changes-requested and revoke its approval | bookexport.admin.approve |
/bookexport admin history [page] |
List pending/finalized publication records newest first | bookexport.admin.history |
/bookexport admin history show <manifest-id> |
Show one retained publication record by its stable UUID | bookexport.admin.history |
/bookexport admin recovery or /bookexport admin recovery list [page] |
List interrupted or residual publication journals newest first without changing files | bookexport.admin.recovery |
/bookexport admin recovery show <transaction-id> |
Checksum-reconcile one complete transaction UUID without changing files | bookexport.admin.recovery |
/bookexport admin publish <staged-file> [fail|unique|replace] |
Publish a staged draft; omitted mode uses publish-collision-mode |
bookexport.admin.publish; replace also needs bookexport.admin.replace |
/bookexport admin reload |
Reload and validate config.yml |
bookexport.admin.reload |
/bookexport admin debug [runtime|book|cmi|workflow|preview [title]] |
Use the complete read-only debug family through the admin route | bookexport.admin.debug; a custom preview title also needs bookexport.export.custom-title |
/bookexport list [page] |
Backward-compatible published-list shortcut | bookexport.admin.list |
/bookexport list <published|staged|archive|backups> [page] |
Scoped list shortcut | Matching list permission |
/bookexport reload |
Compatibility shortcut for admin reload | bookexport.admin.reload |
/bookexport debug [runtime] |
Show Java, Paper, build, and failure diagnostics | bookexport.admin.debug |
/bookexport debug book |
Inspect held-book type and size without showing content | bookexport.admin.debug |
/bookexport debug cmi |
Show detected CMI stack and renderer settings | bookexport.admin.debug |
/bookexport debug workflow |
Show config compatibility mode, workflow directories, counts, and collision mode | bookexport.admin.debug |
/bookexport debug preview [title] |
Preview destination scope, sanitized filename candidate, pages, UTF-16 units, and bytes without writing | bookexport.admin.debug; a custom title also needs bookexport.export.custom-title |
All information, administration, review, history, recovery, list, publish, and debug commands work from the console except held-book inspection, preview, and export/stage.
When multiple list pages exist, player Previous/Next controls run the adjacent list command and preserve the selected scope. A filename can be clicked to copy it. Staged rows identify unreviewed, approved, changes-requested, changed, already-published, association-mismatch, missing, corrupt, or legacy state and expose only actions the sender may use. Review is read-only; Approve, Changes, and Publish controls suggest commands for deliberate submission. Publish continues to suggest /bookexport admin publish <file> fail, never executes immediately, and never inherits a configured replacement policy. Console output remains readable, and console publishers type the explicit command manually.
# Stage a signed book using its signed title in the default workflow
/bookexport
# Explicitly stage any held book under a chosen title
/bookexport stage July News
# Follow the configured workflow under a chosen title
/bookexport export July News
# Export a title that is also a reserved subcommand
/bookexport export info
# Inspect runtime and workflow health
/bookexport info
/bookexport version
/bookexport status
/bookexport admin status
/bookexport debug runtime
/bookexport debug cmi
/bookexport debug workflow
# Preview without writing
/bookexport debug preview July News
# List workflow scopes and preserve scope while paging
/bookexport list
/bookexport list published 2
/bookexport list staged
/bookexport admin list archive 1
/bookexport admin list backups
# Inspect, approve, or request changes without exposing draft content
/bookexport admin review july_news.txt
/bookexport admin approve july_news.txt
/bookexport admin changes july_news.txt
# Browse content-free manifest history and inspect a stable record
/bookexport admin history 2
/bookexport admin history show 123e4567-e89b-12d3-a456-426614174000
# Inspect interrupted publication metadata without changing any file
/bookexport admin recovery list
/bookexport admin recovery show 323e4567-e89b-12d3-a456-426614174000
# Publish only when no case-insensitive target exists
/bookexport admin publish july_news.txt fail
# Publish under july_news_1.txt when july_news.txt already exists
/bookexport admin publish july_news.txt unique
# Replace july_news.txt after creating a timestamped backup
/bookexport admin publish july_news.txt replace
# Apply an edited config safely
/bookexport admin reload
| Permission | Default | Purpose |
|---|---|---|
bookexport.admin |
OP | Grants every documented non-replacing capability, including staging, review decisions, history, read-only recovery, scoped lists, and publication; deliberately excludes replacement |
bookexport.export |
OP | Process the held book through the configured workflow or explicit stage route |
bookexport.export.custom-title |
OP | Override the signed title or name a writable-book export |
bookexport.info |
Everyone | View public plugin and compatibility information |
bookexport.help |
Everyone | View permission-filtered help |
bookexport.admin.status |
OP | View paths, settings, and output health |
bookexport.admin.list |
OP | List published filenames |
bookexport.admin.list.staged |
OP | List staged draft filenames and receive publish suggestions |
bookexport.admin.list.archive |
OP | List archived draft filenames |
bookexport.admin.list.backups |
OP | List replacement backup filenames |
bookexport.admin.review |
OP | View manifest metadata, review state, and current checksum integrity |
bookexport.admin.approve |
OP | Approve the current draft bytes or mark a draft changes-requested |
bookexport.admin.history |
OP | List and inspect retained publication records |
bookexport.admin.recovery |
OP | List and inspect content-free journal state and checksum observations; cannot mutate files |
bookexport.admin.publish |
OP | Publish staged drafts with fail or unique, and enter the publish workflow |
bookexport.admin.replace |
False | Use the backed-up replace collision mode; independent and not inherited by bookexport.admin |
bookexport.admin.reload |
OP | Reload configuration |
bookexport.admin.debug |
OP | View runtime, workflow, CMI, book-size, and preview diagnostics |
Legacy aliases remain available for existing LuckPerms data:
| Legacy node | Default | Grants |
|---|---|---|
exportbook.command |
False | bookexport.admin, therefore every non-replacing capability but not bookexport.admin.replace |
exportbook.export |
False | bookexport.export and bookexport.export.custom-title |
exportbook.list |
False | Published listing through bookexport.admin.list |
exportbook.help |
False | bookexport.help |
exportbook.reload |
False | bookexport.admin.reload |
BookExport relies on Bukkit permission inheritance. It does not manually bypass a denied child node when a master node is present. Replacement is intentionally outside both the current and legacy master nodes.
| Mode | Normal /bookexport and export behavior |
Explicit stage behavior |
|---|---|---|
staged |
Write a unique draft into staging-directory |
Write a unique draft into staging-directory |
direct |
Write immediately into exported-books-directory with a unique suffix when needed |
Still write a unique draft into staging-directory |
Fresh config version 3 files default to staged. Existing version 2 files load in direct compatibility mode, regardless of any undeclared workflow key, until deliberately migrated.
| Scope | Default directory | Contents | List permission |
|---|---|---|---|
published |
~/plugins/CMI/CustomText/ |
Live CMI CustomText files | bookexport.admin.list |
staged |
plugins/BookExport/staging/ |
Drafts awaiting review | bookexport.admin.list.staged |
archive |
plugins/BookExport/archive/ |
Timestamped copies of successfully published drafts | bookexport.admin.list.archive |
backups |
plugins/BookExport/backups/ |
Timestamped copies created before replacement | bookexport.admin.list.backups |
/bookexport list [page] and /bookexport admin list [page] continue to mean the published scope for backward compatibility.
Manifest sidecars and transaction journals are workflow metadata rather than additional .txt scopes. They are excluded from normal file lists and are never copied into CMI's CustomText directory.
A managed staged file such as server_rules.txt has a strict UTF-8 properties sidecar named server_rules.txt.bookexport-manifest.properties. The sidecar uses schema version 1, a monotonically increasing revision, and a stable UUID so its record remains unambiguous even when unique publication changes the final filename or a later draft reuses the intended filename.
Each manifest records content-free provenance and integrity data:
| Group | Recorded fields |
|---|---|
| Identity | Schema version, stable manifest UUID, revision, and native or legacy-adopted origin |
| Names | Intended filename and actual staged filename |
| Source | Native creator name/UUID, signed book author when present, and UTC creation time; a legacy record instead identifies the adopter and adoption time |
| Size | Source pages, Java UTF-16 units, and rendered UTF-8 bytes; unavailable legacy source counts remain explicitly unknown |
| Initial integrity | SHA-256 of the staged .txt bytes |
| Review | unreviewed, approved, or changes-requested; decision actor/time, exact reviewed byte count and SHA-256, and whether approval was implicit |
| Publication | staged, published-archive-pending, or published; publisher, UTC publication time, collision mode, and final filename |
| Outcome | Published SHA-256 (the exact effective review fingerprint), archive filename, and replacement backup filename/byte count/SHA-256 when applicable |
The manifest never contains Minecraft page text or the rendered CustomText body. Server-log audit messages likewise omit those bodies; they intentionally include private metadata such as filenames, actors, stable IDs, counts, and checksums.
Review is recommended, not a new mandatory step for every existing workflow:
- A newly staged managed draft starts
unreviewedwith publication statestaged. /bookexport admin review <file>recalculates integrity and shows manifest metadata without showing the draft body./bookexport admin approve <file>approves its current bytes and stores the reviewing actor, time, and SHA-256./bookexport admin changes <file>records changes-requested and revokes approval. It must be approved before publication.- An unchanged
unreviewedmanaged draft may still be published for compatibility. Publication records the publisher as the implicit approving actor. - A staged legacy
.txtfile without a sidecar may still be published. Its new record uses a legacy origin, preserves unknown source fields as unknown, and records the publisher's implicit approval. - If a managed draft's bytes no longer match the checksum that defines its current review state, publication stops and retains the draft until an administrator reviews and approves the changed bytes.
- A corrupt managed manifest fails closed. Repair or restore the sidecar before publication; BookExport does not silently treat it as an untracked legacy file.
- A malformed or case-ambiguous active sidecar is omitted only from history discovery so unrelated valid publication records remain listable. Direct review, approval, changes, and publication still fail closed for that draft, and status counts the error.
- A leftover
.bookexport-creatingmarker also fails closed. It identifies an interrupted native stage operation whose source metadata must not be silently replaced by legacy adoption.
/bookexport admin history [page] lists retained pending or finalized publication records newest first. /bookexport admin history show <manifest-id> shows the content-free lifecycle metadata, including whether archival is still pending, the final filename, and the publication outcome.
The optional command mode overrides the configured publish-collision-mode for that one publication. Command replace maps to configuration value replace-with-backup.
| Mode | When a case-insensitive published name exists | When no target exists |
|---|---|---|
fail |
Stop without changing the published file; retain the staged draft | Publish with the staged filename |
unique |
Publish as _1, _2, and so on |
Publish with the staged filename |
replace / replace-with-backup |
Copy the current published file to backup-directory, then atomically replace it |
Stop and retain the staged draft; use fail or unique for a new file |
Publication first selects exact live, UUID-bearing archive, and optional UUID-bearing backup filenames. It stores that plan atomically as plugins/BookExport/transactions/<transaction-uuid>.bookexport-transaction.properties before any backup or live mutation. The journal contains only IDs, revisions/states, timestamps, publisher identity, collision mode, basename-only filenames, byte counts, SHA-256 values, and a checksum of the workflow roots—never book pages or rendered CustomText.
The durable protocol advances through these states:
| State | Durable fact |
|---|---|
prepared |
The exact content-free plan exists; no backup or live mutation was authorized before this record. |
backup-created |
A replacement backup containing the exact old live bytes exists. Replacement only. |
live-committed |
The reviewed bytes were committed at the planned live filename. |
manifest-checkpointed |
The active manifest records published-archive-pending. |
archive-created |
The exact reviewed bytes exist at the planned archive filename. |
staged-removed |
The staged .txt source was removed after live/archive verification. |
finalized |
Final archive manifest history is durable; normal completion then deletes the temporary journal. |
Every file mutation is followed by its journal update. File contents and directory entries are forced to durable storage; state updates use compare-and-swap revisions. If a process, host, or I/O failure lands between those boundaries, the journal remains. Startup and /bookexport admin recovery list|show only compare the current staged, live, archive, backup, and manifest facts with recorded checksums. Readable unresolved records block the matching draft, staged name, or planned live name; unreadable records block publication globally because their scope cannot be trusted. A completed residual journal is reported informationally.
The scanner reports one of nine explicit assessments: abandoned-before-live-commit, backup-created-no-live-commit, live-commit-needs-checkpoint, checkpoint-needs-archive, archive-needs-source-cleanup, archive-needs-manifest-finalize, completed-journal-remains, conflict-requires-manual-review, or unreadable-requires-manual-review. Detail output also reports whether each named artifact is missing, matches the reviewed checksum, matches the pre-replacement checksum, mismatches, is ambiguous, is unreadable, or is not applicable.
Recovery inspection is intentionally passive and idempotent. BookExport never automatically replays, repairs, retries, republishes, rolls back, restores, deletes, completes archival, promotes a manifest, cleans a journal, or reloads CMI. Preserve the files and use the troubleshooting procedure for manual review. This journal protects reviewed staged /bookexport admin publish; direct compatibility-mode exports do not create manifests, archives, backups, or transaction journals. The remaining cross-process locking limitation is tracked separately in the backlog.
BookExport deliberately does not execute /cmi reload; an administrator remains responsible for reviewing the published file and refreshing CMI.
These internal placeholders work in filename-format:
| Placeholder | Value |
|---|---|
%title% |
Requested title, or signed title when no custom title is supplied |
%book_title% |
Signed book title, or untitled |
%author% |
Signed book author, or unknown |
%player% |
Exporting player's current name |
%uuid% |
Exporting player's UUID |
%date% |
Export date as yyyy-MM-dd |
%time% |
Export time as HH-mm-ss |
%timestamp% |
Export timestamp as yyyyMMdd-HHmmss |
%pages% |
Source page count |
Replacement is single-pass: placeholder-looking text inside a title or author is kept as literal value data rather than expanded a second time.
These internal placeholders work in pagination-markup:
| Placeholder | Value |
|---|---|
%pageNumber% |
Current 1-based source page number |
%pages% |
Total source page count |
BookExport does not register a PlaceholderAPI expansion and does not resolve PAPI or CMI placeholders inside book content. Text such as %cmi_user_display_name% is exported unchanged so CMI can resolve it for the player who views the CustomText later.
With the packaged defaults, a three-page book becomes:
<AutoPage>
Minecraft page 1
<NextPage>
Minecraft page 2
<NextPage>
Minecraft page 3
Important behavior:
<NextPage>is never generated before source page 1.- The controlled first line prevents book content from accidentally becoming CMI's first-line directive.
- Filenames are lowercase by default because CMI treats CustomText names case-insensitively.
- Draft writes and direct-mode exports use unique names; publication uses the selected collision policy.
- Run
/cmi reloadafter publishing or directly exporting a CustomText file. - CMI markup in the original book remains active by design. Restrict export and publication permissions accordingly.
The format follows the official CMI CustomText documentation.
Paper 26.2 exposes writable books with up to 100 pages and up to 1,024 Java UTF-16 code units per editable page. Signed titles are limited to 32 characters. Visible page capacity is not a fixed character count: it depends on glyph width, formatting, wrapping, and line breaks.
BookExport therefore:
- does not reflow, shorten, or merge valid source pages;
- preserves explicit newlines, blank lines, Unicode, and page order;
- reads written-book pages through modern Adventure components;
- serializes visible text, colors, and decorations into the selected text profile;
- cannot represent hover events, click events, insertion events, selectors, or other interactive component behavior in a plain
.txtfile; - reports raw page and UTF-16 unit statistics through
/bookexport debug book.
| Key | Default | Meaning |
|---|---|---|
config-version |
3 |
Configuration schema marker; older version 2 files receive direct compatibility behavior |
workflow-mode |
staged |
staged for review-first normal exports or direct for immediate unique publication |
staging-directory |
staging |
Draft directory |
archive-directory |
archive |
Timestamped successfully published draft history |
backup-directory |
backups |
Timestamped pre-replacement history |
exported-books-directory |
~/plugins/CMI/CustomText/ |
Published destination; existing key retained for compatibility |
publish-collision-mode |
fail |
Default publication mode: fail, unique, or replace-with-backup; replace is accepted as an alias for the replacement mode |
filename-format |
%title% |
Filename template before sanitation |
lowercase-filenames |
true |
Avoid CMI name collisions on case-sensitive filesystems |
maximum-filename-length |
96 |
Maximum final base length in code points, clamped to 16-160; filesystem byte safety may shorten it |
pagination |
true |
Preserve page boundaries with a marker |
pagination-markup |
<NextPage> |
Marker written between pages |
pagination-on-first-page |
false |
Also write the marker before page 1; leave false for CMI |
cmi-document-header |
<AutoPage> |
Controlled first line in cmi mode |
book-meta |
false |
Add title, author, exporter, time, page, and UTF-16 unit metadata |
color-code-handling |
cmi |
vanilla, legacy, strip, cmi, or mini |
list-page-size |
10 |
Filenames shown per list page, clamped to 1-50 |
debug-logging |
false |
Add content-free stage/direct-export statistics; review and publication audit metadata is logged independently |
Build 019 keeps config-version: 3 and adds no journal, manifest, or approval configuration keys. Managed sidecars and the fixed internal transaction directory are automatic, and explicit approval remains recommended rather than globally required so unchanged unreviewed and legacy drafts keep their compatible publication behavior.
stagingbecomesplugins/BookExport/staging/.~/plugins/CMI/CustomText/starts at the Paper server root.- An absolute path is used as configured.
- A relative path containing
..may not escapeplugins/BookExport/. - Staging, published, archive, backup, and the fixed
plugins/BookExport/transactions/directory must all be writable and resolve to distinct, non-overlapping locations. - Workflow directories may not be symbolic links. Staged publication candidates must be direct, regular, non-symbolic-link
.txtfiles. - A managed manifest is a direct sibling of its staged
.txt; BookExport does not follow a manifest symbolic link or accept a sidecar associated with another path. - Manifest and creation-marker associations are resolved case-insensitively, and ambiguous case variants fail closed on case-sensitive filesystems.
- Startup fails safely when a workflow or transaction directory cannot be created, validated, or written. If transaction storage later becomes missing or unreadable, reviewed publication blocks rather than falling back to an unjournaled write.
- A rejected reload leaves the previous validated runtime settings active.
Version 2 is supported as a compatibility state, not silently upgraded:
- The existing file loads without being rewritten.
- Normal
/bookexport,/bookexport export, and legacy-title routes retain direct publication behavior. - Existing exports are not moved.
/bookexport stage [title]is available and always stages.- Published listing remains the default list behavior.
To opt in to config version 3:
- Back up
plugins/BookExport/config.ymland any existing BookExport/CMI text files. - Add
workflow-mode, the three workflow directory keys, andpublish-collision-modeusing the packaged config as a reference. - Confirm the staging, published, archive, backup, and fixed transaction paths are distinct and do not contain one another.
- Set
config-version: 3last. - Restart Paper, or run
/bookexport admin reloadif only valid BookExport settings changed. - Confirm
/bookexport admin statusand/bookexport debug workflowshow staged mode, five writable directories, and a clear recovery journal. - Stage and publish a disposable test book before migrating production authoring.
A config version newer than this build supports is rejected instead of being guessed at.
| Mode | Result |
|---|---|
vanilla |
Keep valid and literal section-sign sequences unchanged |
legacy |
Convert valid section-sign colors/decorations to ampersand form |
strip |
Remove valid colors, decorations, and resets; preserve malformed/literal section signs |
cmi |
Convert colors to {#RRGGBB} and decorations/resets to & codes |
mini |
Convert colors and decorations to MiniMessage tags; full component-aware style fidelity is a planned improvement |
Hex input is validated before conversion. Malformed sequences are treated as text rather than blindly consuming nearby characters.
- Unicode letters and digits are retained and normalized with Unicode NFKC.
- Path separators, control characters, and unsafe filesystem punctuation are removed.
- Whitespace becomes a single underscore.
- Windows reserved device names are prefixed safely.
- The configured length limit, including collision suffixes, is applied by Unicode code point.
- The final
.txtcomponent also stays within a conservative 255-byte UTF-8 filesystem limit. - CMI filenames are lowercase by default.
- Existing names are checked case-insensitively.
- Draft and direct writes are fully written to a temporary file before a no-replace move and receive
_1,_2, and later suffixes when needed. - Staged publication uses its explicit or configured collision mode; only
replacemay modify an existing target, and it first creates a timestamped backup.
servers/, build output, caches, logs, IDE files, and local OS metadata are excluded by.gitignore.- Debug output reports sizes and selected validated settings, never page text, server secrets, or the full configuration file.
- Manifests and server-log audit records contain metadata and SHA-256 values, never book pages or the rendered CustomText body.
- Transaction journals and recovery objects/output are also content-free. They use basename-only workflow filenames and never store or display absolute paths through the recovery permission.
- Manifest metadata includes player names, UUIDs, the signed book author, filenames, and timestamps. Treat sidecars as private staff records even though they contain no page content.
- Admin status, review/history/recovery output, and scoped lists can expose filesystem paths, private filenames, actors, timestamps, or checksums and are OP-only by default. Ordinary status shows only aggregate recovery health; detailed transaction metadata requires
bookexport.admin.recovery. - Staged-filename tab completion requires the relevant review, approval, or publication permission together with staged-list permission, so action-only users cannot enumerate private draft names.
- Book metadata can include player name, author, export time, and size statistics when configured. Filename templates can separately include the player's UUID.
- Staging creates a review boundary; it does not make author content safe. CMI actions, placeholders, or reserved directives can become active after publication.
- The staged-list Publish action suggests an explicit
failcommand rather than silently executing it or inheriting a replacement default. - Review is read-only; Approve, Changes, and Publish are confirmation-oriented suggested commands. An approval is tied to one exact checksum.
- A corrupt managed sidecar fails closed instead of being downgraded to an untracked legacy draft.
- Invalid active sidecars cannot suppress unrelated valid history records; they remain blocked from every direct or mutating draft operation and are counted by status health.
- Replacement requires an independent permission, always creates a backup, and is excluded from both master nodes.
- Publication rejects path traversal, symlink candidates, ambiguous case-insensitive matches, and non-regular files.
- Recovery list/show and startup scanning are read-only and never provide a mutating click action or invoke CMI.
Run the complete verification suite:
./gradlew clean build --warning-mode all
The build:
- uses the installed Java 25 toolchain;
- targets Paper API
26.2.build.84-stable; - treats all Java compiler warnings as errors;
- runs JUnit 6.1.0 regression tests;
- creates and verifies plugin, source, and Javadoc JARs under
build/libs/; - rejects stale BookExport versions/builds, Java targets, Paper targets/APIs/builds/channels/JARs, artifact examples, and JDK patch versions across every maintained documentation page.
The main artifact uses this naming scheme:
1MB-BookExport-v<version>-<build>-j<java>-<minecraft>.jar
Build 019 is the next monotonic BookExport release build. Release build numbers are intentionally independent of Git commit counts so an uncommitted release candidate does not need an artificial commit sequence.
The release candidate was verified on 2026-07-28 before publication:
./gradlew clean build --warning-mode allcompleted on JDK 25.0.4 with 253 tests: 251 passed, zero failures/errors, and two expected case-variant skips on case-insensitive APFS. It uses--release 25, treats compiler warnings as errors, and verifies generated resources, the JAR manifest, Java class version, all three release JARs, artifact names, and release metadata across every maintained documentation page.- The main plugin class is Java class-file major version 69, and the packaged descriptor declares BookExport 2.0.2 with
api-version: 26.2. - Paper 26.2 STABLE build 84 is installed as
Paper-26.2.jar; PaperScript verifies its saved and installed SHA-256 asdefe82c1c89067186895de34cf32983e9f5a2ea387cfe7597c020faebb98ca16. - Build 019 is smoke-tested through clean startup, metadata/status/recovery commands, and shutdown on Oracle Java 25.0.4 and 26.0.2 with CMI 9.8.8.5, CMILib 1.5.9.9, LuckPerms 5.5.59, and PlaceholderAPI 2.12.3.
- Neither smoke test emitted a BookExport warning, error, exception, or deprecated-API message. JVM startup did report Paper-bundled JOML's terminally deprecated
sun.misc.Unsafe::objectFieldOffsetuse on both runtimes; Java 26 additionally reported LuckPerms-bundled Commodore final-field mutation. These third-party warnings did not originate in BookExport. /bookexport versionis an exact information alias and/bookexport statusis an exact admin-status alias; neither can fall through to the legacy custom-title export route.- The automated suite adds 44 reachable collision-mode/crash-boundary scenarios, three complete publication modes, strict transaction codec/store durability, checksum reconciliation, restart-idempotent zero-write scans, scoped/global blocking, malformed-journal handling, direct-mode isolation, and sentinel privacy. Earlier manifest, renderer, filename, command, and Paper/CMI integration coverage remains in place.
Final artifact SHA-256:
b2c55799ba63e7c7885eb568ff38e0a4d375f697857cb16fdd1e5ec3a26825f5 1MB-BookExport-v2.0.2-019-j25-26.2.jar
This automated and console verification does not replace the repository's in-game beta review.
For runtime validation, use the repository's beta tester checklist. Planned hardening and feature ideas remain in the source repository's feature backlog; neither project-management file is copied into the central player-documentation namespace.
Paper 26.2 requires Java 25 or newer. Confirm java -version for the process that starts Paper.
This release declares api-version: 26.2 intentionally. Older servers are unsupported.
Writable books have no signed title. Use /bookexport stage <title> or /bookexport export <title> and grant bookexport.export.custom-title.
Staging does not change the published directory. Review /bookexport list staged, inspect /bookexport admin review <file>, approve the reviewed bytes when appropriate, publish the draft, confirm /bookexport list published, then run /cmi reload.
This is intentional compatibility behavior. Explicit approval is recommended but non-blocking for an unchanged unreviewed managed draft or an older untracked .txt. BookExport records the publisher as the implicit approving actor and stores the exact published checksum in the review decision.
The current .txt bytes no longer match the checksum that defines the draft's review state. The draft was kept. Inspect it again with /bookexport admin review <file>, then run /bookexport admin approve <file> to approve the current bytes or restore the reviewed version.
BookExport fails closed for a managed sidecar and does not pretend it is a legacy draft. Restore or repair <draft>.bookexport-manifest.properties, verify it with the review command, and approve the current draft before retrying. Do not delete the sidecar merely to bypass its recorded integrity state.
BookExport found <draft>.bookexport-creating, which means the server or filesystem operation stopped after reserving a native draft name but before completing its manifest pair. Do not publish or delete the marker as a bypass. Inspect the staged file and logs; remove both incomplete files only when you have intentionally abandoned that stage attempt, then export the original book again to preserve author, timestamp, page, and checksum provenance.
A reviewer used /bookexport admin changes <file>. Review the revised .txt, then explicitly approve its current bytes before publication.
Run /bookexport admin history [page], copy the stable manifest UUID, and use /bookexport admin history show <manifest-id>. The record reports final filename, checksum, actor, collision mode, archive, backup, and outcome without displaying content.
An existing config version 2 deliberately uses direct compatibility mode. BookExport does not rewrite it. Follow the version 2 migration procedure to opt in to staged mode.
The default fail policy protects the current live text. Review both files, then publish with unique or ask an administrator with the separate replacement permission to use replace.
This is intentional. Grant bookexport.admin.replace separately. Replacement also fails when no published target exists; use fail or unique to create a new text.
The published file is already live. Do not retry. Run /bookexport admin recovery list, inspect the matching complete UUID with recovery show, preserve the staged/live/archive/backup/manifests/journal set, and follow the checksum-based manual reconciliation procedure. BookExport performs no automatic repair or CMI reload.
Startup reports only aggregate counts. Use /bookexport admin recovery list with the dedicated recovery permission, then show <complete-transaction-uuid> for content-free state, filenames, counts, checksums, and artifact observations. A readable record blocks its affected draft/staged/live names; an unreadable record blocks all reviewed publication because its scope cannot be trusted. Repeated startup/status/list/show scans are read-only and do not advance or clean a journal.
A case-insensitive equivalent already exists. Draft and direct exports always choose a unique name; unique publication does the same.
Confirm /bookexport list published, run /bookexport debug cmi, then run /cmi reload before /cmi ctext <name> <player>.
The generated separator is correct. Check whether the original book itself contains a line equal to <NextPage> or other intentional CMI markup.
Read the server log and correct the invalid path or value. Confirm all four configurable workflow directories and the fixed transaction directory are distinct and non-overlapping. The previous validated runtime settings remain active.
- Player documentation: docs.1moreblock.com/custom-server-plugins/bookexport/
- Source: mrfdev/1MB-CMI-BookExport
- Author: mrfloris
- License: use at your own risk; no warranty. Credit is appreciated.